理解元类的本质
在 Python 中,类本身也是对象,而元类就是创建这些类对象的“类”。默认情况下,所有类的元类是type
。例如:
class Foo(object):
pass
等价于:
Foo = type("Foo", (object,), {})
自定义元类的方法
定义元类需要继承type
,并重写__new__
、__init__
或__call__
方法:
class MyType(type):
def __new__(cls, name, bases, namespace):
new_cls = super().__new__(cls, name, bases, namespace)
print(f"类 {name} 被创建")
return new_cls
使用自定义元类:
class Bar(metaclass=MyType):
pass
运行后会输出:类 Bar 被创建
。
元类控制类的生命周期
元类的三个核心方法分别控制不同阶段:
class MyType(type):
def __new__(cls, name, bases, namespace):
new_cls = super().__new__(cls, name, bases, namespace)
print("__new__: 创建类对象")
return new_cls
def __init__(self, name, bases, namespace):
print("__init__: 初始化类成员")
super().__init__(name, bases, namespace)
def __call__(self, *args, **kwargs):
print("__call__: 创建实例")
return super().__call__(*args, **kwargs)
实例化过程:
obj = MyClass()
# 输出顺序:__new__ → __init__ → __call__
元类的实际应用场景
- 强制类属性规范
在元类的__init__
中检查类是否包含必需属性:
if "required_attr" not in namespace:
raise TypeError("缺少 required_attr 属性")
- 自动注册类
将类自动添加到全局注册表:
registry = {}
class RegisterMeta(type):
def __init__(cls, name, bases, namespace):
registry[name] = cls
super().__init__(name, bases, namespace)
- 实现单例模式
通过__call__
控制实例化次数:
_instance = None
class SingletonMeta(type):
def __call__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__call__(*args, **kwargs)
return cls._instance
- 动态修改类方法
在元类中为所有方法添加装饰器:
for name, obj in namespace.items():
if callable(obj):
namespace[name] = decorator(obj)
元类与继承的关系
子类会继承父类的元类。如果父类使用自定义元类,其子类也会自动使用同一元类:
class Parent(metaclass=MyType):
pass
class Child(Parent): # 自动使用 MyType 作为元类
pass
注意事项
- 元类会增加代码复杂性,仅在需要全局类行为控制时使用
- 大多数场景可以通过装饰器或普通继承实现相同功能
- 框架开发(如 ORM、API 生成)是元类的典型应用场景