6月2日 01:32
Python 元类是什么?type 怎么创建类?元类什么时候该用?
元类是创建类的类。普通类创建实例,元类创建类。Python 里 class 语句本质上是调用 type() 来创建类对象,元类让你拦截这个过程,在类创建时自动修改类的属性、方法、继承关系。
Python 类的创建过程
pythonclass Foo: x = 1
这行代码执行时,Python 做了这件事:
pythonFoo = type('Foo', (object,), {'x': 1})
type(类名, 父类元组, 属性字典) 就是创建类的底层调用。type 本身就是一个元类——所有类都是 type 的实例。
pythonprint(type(Foo)) # <class 'type'> print(type(Foo())) # <class '__main__.Foo'>
type(Foo) 是 type,说明 Foo 类是 type 的实例。type(Foo()) 是 Foo,说明 Foo() 实例是 Foo 的实例。
自定义元类
继承 type,重写 __new__ 或 __init__:
pythonclass Meta(type): def __new__(cls, name, bases, dct): # 在类创建前修改属性字典 dct['created_by_meta'] = True return super().__new__(cls, name, bases, dct) class Foo(metaclass=Meta): x = 1 print(Foo.created_by_meta) # True
__new__ 在类对象创建之前调用,可以修改 dct(属性字典)。__init__ 在类对象创建之后调用,可以修改已创建的类。大多数场景用 __new__ 就够了。
实际用途
1. 自动注册子类
ORM、插件系统常用——每定义一个子类就自动注册到一个全局字典里:
pythonclass RegistryMeta(type): _registry = {} def __new__(cls, name, bases, dct): klass = super().__new__(cls, name, bases, dct) if name != 'Base': # 跳过基类本身 cls._registry[name] = klass return klass class Base(metaclass=RegistryMeta): pass class User(Base): pass class Order(Base): pass print(RegistryMeta._registry) # {'User': <class 'User'>, 'Order': <class 'Order'>}
Django 的 ModelBase 就是这种模式——每个 Model 子类自动注册到 Django 的 app registry。
2. 接口检查
强制子类实现特定方法:
pythonclass InterfaceMeta(type): def __new__(cls, name, bases, dct): if bases: # 不是基类本身 required = getattr(bases[0], '_required_methods', []) for method in required: if method not in dct: raise TypeError(f'{name} 必须实现 {method}') return super().__new__(cls, name, bases, dct) class Animal(metaclass=InterfaceMeta): _required_methods = ['speak'] class Dog(Animal): def speak(self): return 'Woof!' class Cat(Animal): pass # TypeError: Cat 必须实现 speak
3. 单例模式
pythonclass SingletonMeta(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super().__call__(*args, **kwargs) return cls._instances[cls] class Database(metaclass=SingletonMeta): pass
重写 __call__ 拦截实例化过程——第一次创建实例,后续返回同一个。
追问
元类和类装饰器有什么区别?
类装饰器在类创建之后修改,元类在类创建过程中修改。类装饰器更简单透明,优先用装饰器。元类能控制 __new__ 和 __init__,能做的事更多但也更难调试。
什么时候该用元类?
几乎不需要。Python 社区有一句话:"如果你不确定是否需要元类,你就不需要。"95% 的场景用类装饰器、__init_subclass__、或普通继承就能解决。元类适合框架作者(Django ORM、SQLAlchemy),应用层开发者很少需要。