元类(metaclass)是 Python 中一个高级且相对较少使用的概念。元类可以被视为类的类,它控制类的创建过程。
一、基本概念
在 Python 中,一切皆对象。为了避免混淆,我们约定两个术语:
- 类实例:当我们定义一个类时,实际上是在创建一个对象,这个对象就是类本身,我们将类本身这个对象称为
类实例
。 - 类的实例:我们将使用类创建的实例称之为
类的实例
。
生活中的例子:
- 我们可以将
元类
理解为制作蛋糕模具的机床
,将类
理解为制作蛋糕的模具
。 制作蛋糕模具
是元类创建的类实例
,蛋糕
是蛋糕模具创建的蛋糕类的实例
。
二、基本原理
元类
控制 类实例
的创建过程,其中 __new__
方法用于创建 类实例
,而 __init__
方法用于初始化这个 类实例
。
类
控制 类的实例
的创建过程,其中 __new__
方法用于创建 类的实例
,而__init__
方法用于初始化这个 类的实例
。
三、核心作用
元类的核心作用是控制类的创建过程,允许我们在类被实际创建之前修改它,这使得我们可以在类级别上进行高级的定制,例如添加额外的属性、修改类的行为等。
四、Demo 示例
示例 1:简单的元类
class SimpleMeta(type): registered_classes = [] def __new__(cls, name, bases, dct): """创建类实例""" print("Generate new instance") return super().__new__(cls, name, bases, dct) def __init__(cls, name, bases, dct): """初始化类实例""" print("Init new instance") super().__init__(name, bases, dct) SimpleMeta.registered_classes.append(cls) class MyClass1(metaclass=SimpleMeta): pass print('========================================') class MyClass2(metaclass=SimpleMeta): pass print('========================================') print(f"Registered classes: {SimpleMeta.registered_classes}")
输出结果:
Generate new instance Init new instance ======================================== Generate new instance Init new instance ======================================== Registered classes: [<class '__main__.SimpleMeta'>, <class '__main__.SimpleMeta'>]
示例说明:
元类 SimpleMeta 中的 __init__ 方法在 __new__ 方法执行后被调用,用于收集已注册的类的信息,展示了元类的实际用途。
示例 2:蛋糕模具定制
class ShapeMeta(type): def __new__(cls, name, bases, dct): # 获取类的名称并根据不同的类名进行定制 if name == 'RoundCake': # 定制化操作 dct['shape'] = 'Round' if name == 'TriangleCake': # 定制化操作 dct['shape'] = 'Triangle' return super().__new__(cls, name, bases, dct) class RoundCake(metaclass=ShapeMeta): pass class TriangleCake(metaclass=ShapeMeta): pass my_round_cake = RoundCake() my_triangle_cake = TriangleCake() print(my_round_cake.shape) # 输出 Round print(my_triangle_cake.shape) # 输出 Triangle
输出结果:
Round Triangle
示例说明:
元类 ShapeMeta 根据类的名称控制类的形状属性,这里可以看出元类对类创建过程的控制。
综合示例:面向切面编程
import functools def listening(func): @functools.wraps(func) def wrapper(self, *args, **kwargs): print(f'do something before calling function {func.__name__}') result = func(self, *args, **kwargs) print(f'do something after calling function {func.__name__}') return wrapper class ListeningMeta(type): def __new__(cls, name, bases, dct): for key, value in dct.items(): if callable(value) and not key.startswith("__"): dct[key] = listening(value) return super().__new__(cls, name, bases, dct) class MyClass(metaclass=ListeningMeta): def __init__(self, data): self._data = data @property def data(self): print(self._data) return self._data def do_somthing(self): print(f'do_somthing with {self._data}') a = MyClass(1) a.data a.do_somthing()
输出结果:
1 do something before calling function do_somthing do_somthing with 1 do something after calling function do_somthing
示例说明:
元类 ListeningMeta 展示了元类如何用于在不修改原始类代码的情况下添加额外的行为,实现面向切面编程的效果。
五、要点小结
- 元类是类的类,用于控制类实例的创建过程和初始化过程。
__new__
用于创建类实例,__init__
用于初始化实例。- 元类的主要作用是允许在类被创建之前修改它,如添加属性、修改行为。
- 元类适用于对类创建过程进行深度干预的特殊需求,对于大多数情况,普通类定义和继承已经足够,元类提供额外的灵活性。