


























要理解元类(Metaclass),可以这样类比:类是用来创建对象的蓝图;而元类,则是用来创建类的蓝图。如果说类是对象的“工厂”,那么元类就是生产这些“工厂”的“总工厂”。
在 Python 中,一切皆对象,类本身也不例外。一个类,它是其元类的一个实例。
typetype 是 Python 内置的默认元类,所有类(包括 int、str 等)都是 type 的实例。
你可以通过 type() 函数来验证一个对象的类型,也可以使用它来动态地创建类。
type(name, bases, dict) 接收三个参数,动态地返回一个新的类:
name:类的名称(字符串)bases:父类的元组(用于继承)dict:包含属性(方法)的字典# 使用 class 语句定义类
class Hello:
def say_hello(self):
print("Hello!")
# 等价于使用 type 动态创建
def say_hello(self):
print("Hello!")
Hello = type('Hello', (), {'say_hello': say_hello})
# 两者创建出的类是完全一样的
当 Python 解释器遇到 class 关键字时,它背后的工作就是调用元类(默认是 type)来创建这个类。
要创建自定义元类,需要继承 type。你可以重写它的几个关键方法,在类创建的不同阶段进行干预。
__new__ 方法:类的“构造器”这是创建类对象时第一个被调用的方法。它在类的名称、基类、属性字典准备好后被调用。你可以在这里修改类的属性字典(例如,添加、删除或修改属性和方法),然后再调用 super().__new__ 真正创建类。
class UpperAttrMeta(type):
def __new__(cls, name, bases, namespace):
# 将类中所有非特殊属性名转为大写
upper_namespace = {
key.upper(): value
for key, value in namespace.items()
if not key.startswith('__')
}
# 使用修改后的命名空间创建类
return super().__new__(cls, name, bases, upper_namespace)
class Demo(metaclass=UpperAttrMeta):
x = 10
print(Demo.X) # 输出: 10
# print(Demo.x) # 报错: AttributeError
__init__ 方法:类的“初始化器”在 __new__ 创建类对象之后被调用,通常用于对已经创建好的类进行进一步的初始化或设置。
__call__ 方法:控制类的实例化当通过类创建实例时(即 MyClass()),实际上是调用了元类的 __call__ 方法。重写此方法可以控制实例的创建和初始化过程,是实现单例模式(Singleton)的关键。
class SingletonMeta(type):
def __init__(cls, *args, **kwargs):
cls.__instance = None
super().__init__(*args, **kwargs)
def __call__(cls, *args, **kwargs):
if cls.__instance is None:
cls.__instance = super().__call__(*args, **kwargs)
return cls.__instance
class MyClass(metaclass=SingletonMeta):
pass
a = MyClass()
b = MyClass()
print(a is b) # 输出: True
__prepare__ 方法:准备类的命名空间在类的定义体开始执行前被调用,它返回一个字典或映射对象,用于存储类定义体中的属性和方法。在 Python 3 中,这是唯一一个在类体执行前运行的元类方法,极少使用,通常用于控制类中属性的定义顺序等高级场景。
何时使用?
元类常用于框架和库的开发中,以实现高度抽象和自动化:
abc 模块就是通过 ABCMeta 这个元类来实现的。注意事项
元类是 Python 中最复杂、最难理解的特性之一。它强大,但也容易被滥用。在绝大多数情况下,更简单的解决方案(如类装饰器、描述符或继承)是更好的选择。请务必谨记 “KISS 原则”(Keep It Simple, Stupid),仅在确实需要动态且全局地控制类创建行为时才考虑使用元类。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。