跳至主要內容

python元类

pptg大约 4 分钟

1. 什么是元类

在python中,一切皆对象,包括类本身。元类是创建类对象的类。就像类是用来创建实例的模板一样,元类是创建类的模板。

class MyClass:
    pass

obj = MyClass()

print(f"实例的类型: {type(obj)}")        # <class '__main__.MyClass'>
print(f"类的类型: {type(MyClass)}")      # <class 'type'>
print(f"type的类型: {type(type)}")       # <class 'type'>

# 所以:
# 实例 obj 是 MyClass 类的对象
# 类 MyClass 是 type 类的对象
# 元类 type 是 type 类的对象(type是自身的实例)

因此,python的类也可以直接由type创建

# 传统方式创建类
class Person:
    name = "Unknown"
    
    def say_hello(self):
        return f"Hello, I'm {self.name}"

# 等价于使用type动态创建
Person = type(
    'Person', 
    (), 
    {
        'name': 'Unknown',
        'say_hello': lambda self: f"Hello, I'm {self.name}"
    }
)

# 两种方式创建的对象完全一样
p1 = Person()
print(p1.say_hello())  # Hello, I'm Unknown

2. 自定义元类

要自定义元类,需要继承type并重写__new____init__

class MyMeta(type):
    """自定义元类"""
    
    def __new__(cls, name, bases, attrs):
        print(f"🐍 元类 __new__ 被调用!")
        print(f"  创建类: {name}")
        print(f"  基类: {bases}")
        print(f"  属性: {list(attrs.keys())}")
        
        # 可以修改属性
        if 'version' not in attrs:
            attrs['version'] = '1.0.0'
        
        # 自动添加类文档
        if '__doc__' not in attrs or not attrs['__doc__']:
            attrs['__doc__'] = f"这是自动生成的 {name} 类"
        
        # 调用父类的__new__来实际创建类
        return super().__new__(cls, name, bases, attrs)
    
    def __init__(self, name, bases, attrs):
        print(f"🐍 元类 __init__ 被调用!")
        super().__init__(name, bases, attrs)

# 使用自定义元类创建类
class MyClass(metaclass=MyMeta):
    author = "Anonymous"
    
    def method(self):
        return "Hello"

print("=== 创建实例 ===")
obj = MyClass()
print(f"类版本: {MyClass.version}")
print(f"作者: {MyClass.author}")
print(f"文档: {MyClass.__doc__}")
🐍 元类 __new__ 被调用!
  创建类: MyClass
  基类: ()
  属性: ['__module__', '__qualname__', 'author', 'method']
🐍 元类 __init__ 被调用!
=== 创建实例 ===
类版本: 1.0.0
作者: Anonymous
文档: 这是自动生成的 MyClass 类

3. 元类的应用

自动注册子类
class PluginMeta(type):
    """插件系统的元类 - 自动注册所有插件"""
    
    def __init__(cls, name, bases, attrs):
        super().__init__(name, bases, attrs)
        
        # 跳过基类
        if name == 'BasePlugin':
            return
            
        # 初始化注册表
        if not hasattr(cls, 'registry'):
            cls.registry = {}
        
        # 自动注册插件
        plugin_name = attrs.get('plugin_name', name.lower())
        cls.registry[plugin_name] = cls
        print(f"✅ 注册插件: {plugin_name}")

class BasePlugin(metaclass=PluginMeta):
    """插件基类"""
    pass

# 自动注册这些插件类
class EmailPlugin(BasePlugin):
    plugin_name = "email"
    
class SMSPlugin(BasePlugin):
    plugin_name = "sms"
    
class PushPlugin(BasePlugin):
    pass  # 使用类名小写作为名称

print("\n已注册的插件:")
for name, plugin_class in BasePlugin.registry.items():
    print(f"  {name}: {plugin_class}")

4. 类的创建顺序

  • __new__: 创建类对象
  • __init__: 初始化类对象
  • __call__: 创建实例
class MyMeta(type):
    """自定义元类"""
    
    def __new__(cls, name, bases, attrs):
        print(f"🐍 元类 __new__ 被调用!")
        print(f"  创建类: {name}")
        print(f"  基类: {bases}")
        print(f"  属性: {list(attrs.keys())}")
        
        # 可以修改属性
        if 'version' not in attrs:
            attrs['version'] = '1.0.0'
        
        # 自动添加类文档
        if '__doc__' not in attrs or not attrs['__doc__']:
            attrs['__doc__'] = f"这是自动生成的 {name} 类"
        
        # 调用父类的__new__来实际创建类
        return super().__new__(cls, name, bases, attrs)
    
    def __init__(self, name, bases, attrs):
        print(f"🐍 元类 __init__ 被调用!")
        super().__init__(name, bases, attrs)

# 使用自定义元类创建类
class MyClass(metaclass=MyMeta):
    author = "Anonymous"
    
    def method(self):
        return "Hello"

print("=== 创建实例 ===")
obj = MyClass()
print(f"类版本: {MyClass.version}")
print(f"作者: {MyClass.author}")
print(f"文档: {MyClass.__doc__}")
🐍 元类 __new__ 被调用!
  创建类: MyClass
  基类: ()
  属性: ['__module__', '__qualname__', 'author', 'method']
🐍 元类 __init__ 被调用!
=== 创建实例 ===
类版本: 1.0.0
作者: Anonymous
文档: 这是自动生成的 MyClass 类