第 15 章 元类
15.1 一切皆对象:类也是对象
在 Python 中,类本身也是对象——它是 type 的实例:
class Dog:
pass
# Dog 是一个对象
print(type(Dog)) # <class 'type'>
print(type(int)) # <class 'type'>
print(type(str)) # <class 'type'>
print(type(type)) # <class 'type'> — type 是自身的实例
# 类是 type 的实例,对象是类的实例
dog = Dog()
print(type(dog)) # <class 'Dog'>
print(type(Dog)) # <class 'type'>
# 继承关系 vs 实例关系
print(isinstance(dog, Dog)) # True — dog 是 Dog 的实例
print(isinstance(Dog, type)) # True — Dog 是 type 的实例
print(issubclass(Dog, object)) # True — Dog 继承自 object
print(issubclass(type, object)) # True — type 也继承自 object
15.2 type() 动态创建类
type 有两种用法:
type(obj)— 返回对象的类型type(name, bases, dict)— 动态创建类
# 等价于 class Dog(Animal): ...
def bark(self):
return f"{self.name} says Woof!"
Dog = type(
"Dog", # 类名
(object,), # 基类元组
{ # 类属性字典
"species": "Canis familiaris",
"__init__": lambda self, name: setattr(self, "name", name),
"bark": bark,
}
)
dog = Dog("Buddy")
print(dog.bark()) # Buddy says Woof!
print(type(dog)) # <class '__main__.Dog'>
# 动态创建类的实际用途——根据配置生成类
def make_model(name, fields):
def __init__(self, **kwargs):
for field in fields:
setattr(self, field, kwargs.get(field))
def __repr__(self):
attrs = ", ".join(f"{f}={getattr(self, f)!r}" for f in fields)
return f"{name}({attrs})"
return type(name, (object,), {
"__init__": __init__,
"__repr__": __repr__,
"_fields": fields,
})
User = make_model("User", ["name", "age", "email"])
user = User(name="Alice", age=30, email="alice@example.com")
print(user) # User(name='Alice', age=30, email='alice@example.com')
15.3 metaclass 参数
metaclass 指定创建类时使用的元类(默认是 type):
class Meta(type):
pass
class MyClass(metaclass=Meta):
pass
print(type(MyClass)) # <class 'Meta'>
15.4 元类的 __new__ 与 __init__
class Meta(type):
def __new__(mcs, name, bases, namespace):
"""创建类对象之前调用"""
print(f"Meta.__new__: 创建类 {name}")
# 可以修改 name、bases、namespace
cls = super().__new__(mcs, name, bases, namespace)
return cls
def __init__(cls, name, bases, namespace):
"""类对象创建之后调用"""
print(f"Meta.__init__: 初始化类 {name}")
super().__init__(name, bases, namespace)
def __call__(cls, *args, **kwargs):
"""类被调用时(创建实例时)触发"""
print(f"Meta.__call__: {cls.__name__} 被调用")
instance = super().__call__(*args, **kwargs)
return instance
class MyClass(metaclass=Meta):
def __init__(self, x):
self.x = x
# 输出(定义类时):
# Meta.__new__: 创建类 MyClass
# Meta.__init__: 初始化类 MyClass
obj = MyClass(42)
# 输出(创建实例时):
# Meta.__call__: MyClass 被调用
15.5 __prepare__ 控制类命名空间
__prepare__ 返回用于类体执行的命名空间字典:
from collections import OrderedDict
class OrderedMeta(type):
@classmethod
def __prepare__(mcs, name, bases):
return OrderedDict() # 类属性保持定义顺序
def __new__(mcs, name, bases, namespace):
cls = super().__new__(mcs, name, bases, dict(namespace))
cls._field_order = list(namespace.keys())
return cls
class Record(metaclass=OrderedMeta):
name = "str"
age = "int"
email = "str"
print(Record._field_order)
# ['__module__', '__qualname__', 'name', 'age', 'email']
# 禁止重复定义的命名空间
class NoDuplicateDict(dict):
def __setitem__(self, key, value):
if key in self and key != "__module__" and key != "__qualname__":
raise TypeError(f"属性 {key!r} 重复定义")
super().__setitem__(key, value)
class StrictMeta(type):
@classmethod
def __prepare__(mcs, name, bases):
return NoDuplicateDict()
def __new__(mcs, name, bases, namespace):
return super().__new__(mcs, name, bases, dict(namespace))
# class Bad(metaclass=StrictMeta):
# x = 1
# x = 2 # TypeError: 属性 'x' 重复定义
15.6 元类实战
单例模式
class 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):
def __init__(self):
print("初始化数据库连接")
db1 = Database() # 初始化数据库连接
db2 = Database() # 不再初始化
print(db1 is db2) # True
自动注册
class PluginMeta(type):
registry = {}
def __new__(mcs, name, bases, namespace):
cls = super().__new__(mcs, name, bases, namespace)
if bases: # 不注册基类本身
PluginMeta.registry[name] = cls
return cls
class Plugin(metaclass=PluginMeta):
pass
class ImagePlugin(Plugin):
pass
class VideoPlugin(Plugin):
pass
print(PluginMeta.registry)
# {'ImagePlugin': <class 'ImagePlugin'>, 'VideoPlugin': <class 'VideoPlugin'>}
接口检查
class InterfaceMeta(type):
def __new__(mcs, name, bases, namespace):
cls = super().__new__(mcs, name, bases, namespace)
for base in bases:
required = getattr(base, "_required_methods", [])
for method_name in required:
if method_name not in namespace:
raise TypeError(
f"{name} 必须实现方法 {method_name}"
)
return cls
class Serializable(metaclass=InterfaceMeta):
_required_methods = ["serialize", "deserialize"]
# class BadImpl(Serializable): # TypeError: BadImpl 必须实现方法 serialize
# pass
class GoodImpl(Serializable):
def serialize(self):
return "{}"
def deserialize(self, data):
pass
简易 ORM
class ModelMeta(type):
def __new__(mcs, name, bases, namespace):
fields = {}
for key, value in namespace.items():
if isinstance(value, tuple) and len(value) == 2:
field_type, default = value
fields[key] = (field_type, default)
namespace["_fields"] = fields
cls = super().__new__(mcs, name, bases, namespace)
return cls
class Model(metaclass=ModelMeta):
def __init__(self, **kwargs):
for name, (field_type, default) in self._fields.items():
value = kwargs.get(name, default)
if not isinstance(value, field_type):
raise TypeError(f"{name} 应为 {field_type.__name__}")
setattr(self, name, value)
def __repr__(self):
attrs = ", ".join(
f"{k}={getattr(self, k)!r}" for k in self._fields
)
return f"{type(self).__name__}({attrs})"
class User(Model):
name = (str, "")
age = (int, 0)
active = (bool, True)
user = User(name="Alice", age=30)
print(user) # User(name='Alice', age=30, active=True)
15.7 何时使用元类 vs __init_subclass__ vs 类装饰器
三种自定义类创建行为的方式,从简单到复杂:
类装饰器(最简单)
def add_logging(cls):
for name, method in vars(cls).items():
if callable(method) and not name.startswith("_"):
setattr(cls, name, logged(method))
return cls
@add_logging
class MyService:
def process(self):
pass
__init_subclass__(中等复杂度,Python 3.6+)
class Validated:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
for name, value in vars(cls).items():
if callable(value) and hasattr(value, "_validate_args"):
pass # 添加验证逻辑
元类(最强大但最复杂)
class Meta(type):
def __new__(mcs, name, bases, namespace):
# 能修改一切
pass
选择指南:
| 需求 | 推荐方案 |
|---|---|
| 修改类属性或添加方法 | 类装饰器 |
| 注册子类、验证子类 | __init_subclass__ |
| 控制类命名空间、修改类创建过程 | 元类 |
| 控制实例创建 | 元类的 __call__ |
经验法则:能用类装饰器解决的不要用 __init_subclass__,能用 __init_subclass__ 解决的不要用元类。元类是最后的手段。
本章小结:元类是”类的类”——控制类的创建过程。虽然强大,但在大多数项目中很少直接使用。理解元类主要是为了理解 Python 的对象模型和类创建机制。实际开发中,优先考虑类装饰器和
__init_subclass__。