
你或许听过「Python 中一切皆对象」的说法,但你知道这些对象是如何诞生的吗?让我们先从一段熟悉的代码说起:
# 函数定义
def func_a(x: int):
return x * 2
def func_b(x: int):
z = 50
res = func_a(z + x)
return res
# 类继承与MRO
class A:
def say(self):
print("i'm A")
class B(A):
def say(self):
print("im B")
class C(A):
def say(self):
print('im C')
class D(B, C):
def say(self):
super().say()
# 运行结果
d = D()
d.say() # 输出:im B?不!输出:im B?等下看MRO…
mro = D.mro()
print(mro) # 输出:[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]这段代码展示了 Python 的两大核心特性:函数的链式调用和类的多重继承 MRO(方法解析顺序)。但隐藏在这些代码背后的,是 Python 对象模型的三层结构:
instance(实例)→class(类)→metaclass(元类)
我们平时创建的对象都是实例,比如:
d = D() # d是D类的实例
x = func_a(10) # x是func_a的返回值实例实例是由类创建的,比如d = D()中,D就是类。但你有没有想过 ——类本身也是一个对象?
# 验证:类本身是对象
print(type(D)) # 输出:<class 'type'>
print(isinstance(D, object)) # 输出:TrueD是一个类,但它的type()返回的是type,说明D是type的实例!isinstance(D, object)返回True,说明类本身也继承自object。既然类是type的实例,那type就是元类—— 创建类的「类」。元类是 Python 对象模型的顶层,所有元类都继承自type。
元类的核心作用:创建类,并控制类的创建过程。
type是 Python 中最特殊的存在,它有两个身份:
type(123) → <class 'int'>你没看错 ——type可以直接创建类,无需class关键字!它的语法是:
type(类名, 父类元组, 属性与方法字典)比如,我们用type重写前面的D类:
# 创建基类A
A = type('A', (object,), {
'say': lambda self: print("i'm A")
})
# 创建B类,继承自A
B = type('B', (A,), {
'say': lambda self: print("im B")
})
# 创建C类,继承自A
C = type('C', (A,), {
'say': lambda self: print('im C')
})
# 创建D类,继承自B和C
D = type('D', (B, C), {
'say': lambda self: super().say()
})
# 测试
d = D()
d.say() # 输出:im B
print(D.mro()) # 输出:[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]class关键字创建的完全一致!class关键字只是type创建类的「语法糖」。虽然type可以直接创建类,但更多时候,我们需要自定义元类来控制类的创建过程。自定义元类的方法是继承 type。
class MyMetaclass(type):
# 在类创建前被调用
def __new__(cls, name, bases, attrs):
print(f"正在创建类:{name}")
print(f"父类:{bases}")
print(f"属性和方法:{attrs}")
# 必须返回创建好的类
return super().__new__(cls, name, bases, attrs)
# 在类创建后被调用
def __init__(cls, name, bases, attrs):
print(f"已创建类:{cls}")
# 可以在这里添加类的属性或方法
cls.version = "1.0"
super().__init__(name, bases, attrs)
# 使用自定义元类创建类
class MyClass(metaclass=MyMetaclass):
def __init__(self, name):
self.name = name
def say(self):
print(f"Hello, {self.name}")
# 测试
print(f"类版本:{MyClass.version}") # 输出:类版本:1.0
obj = MyClass("Alice")
obj.say() # 输出:Hello, Alice元类可以在类创建的任何阶段插入自定义逻辑,比如:
class UppercaseMetaclass(type):
def __new__(cls, name, bases, attrs):
# 强制类名首字母大写
if not name[0].isupper():
raise ValueError(f"类名必须首字母大写,当前类名:{name}")
return super().__new__(cls, name, bases, attrs)
# 正确的类名
class Person(metaclass=UppercaseMetaclass):
pass
# 错误的类名(会抛出异常)
# class person(metaclass=UppercaseMetaclass):
# passclass RegistryMetaclass(type):
# 类变量,用于存储所有子类
registry = {}
def __new__(cls, name, bases, attrs):
# 创建类
new_class = super().__new__(cls, name, bases, attrs)
# 如果不是基类,则注册
if bases:
cls.registry[name] = new_class
return new_class
# 基类
class BasePlugin(metaclass=RegistryMetaclass):
def execute(self):
pass
# 子类1
class PluginA(BasePlugin):
def execute(self):
print("PluginA执行")
# 子类2
class PluginB(BasePlugin):
def execute(self):
print("PluginB执行")
# 测试:自动注册
print(f"所有插件:{RegistryMetaclass.registry}") # 输出:所有插件:{'PluginA': <class '__main__.PluginA'>, 'PluginB': <class '__main__.PluginB'>}
# 批量执行所有插件
for plugin_name, plugin_class in RegistryMetaclass.registry.items():
plugin = plugin_class()
plugin.execute() # 输出:PluginA执行;PluginB执行在理解元类之前,必须先掌握 Python 的两个核心内置函数:
obj是否是类cls或其子类的实例# 检查实例
print(isinstance(d, D)) # True
print(isinstance(d, B)) # True
print(isinstance(d, C)) # True
print(isinstance(d, A)) # True
print(isinstance(d, object)) # Truecls是否是类base_cls的子类# 检查类
print(issubclass(D, B)) # True
print(issubclass(D, C)) # True
print(issubclass(D, A)) # True
print(issubclass(D, object)) # True
print(issubclass(B, C)) # False(B和C都是A的子类)在 Python 的对象模型中,有一个看似矛盾但又合理的规定:
print(type(object)) # 输出:<class 'type'>
print(isinstance(type, object)) # 输出:True
print(isinstance(object, type)) # 输出:Truetype(object) → type:object是type的实例isinstance(type, object) → True:type是object的实例元类是非常强大但也非常危险的工具,因为它会改变 Python 的对象创建规则。Python 核心开发者的建议是:
「99% 的时间里,你不需要使用元类。如果你认为你需要它,你可能错了。但如果确实需要,那你肯定需要。」
元类的主要适用场景:
以下情况请不要使用元类:
元类是 Python 中最高级别的对象,它的本质是:
创建类的工厂
元类的核心流程是:
class关键字定义一个类时__new__方法创建类__init__方法初始化类元类是 Python 元编程的核心,但它的使用门槛较高,需要对 Python 的对象模型有深入的理解。在实际开发中,我们应该尽量使用更简单的工具(如装饰器、继承)来解决问题,只有在确实需要控制类的创建过程时,才考虑使用元类。