1 Python 元类 - Metaclasses 2 3 默认情况下儿, classes 是有 type() 构造的. 4 类的结构体在一个新的 namespace 被执行, 类的名字 class name 绑定(bound locally)到 5 type(name, bases, namespace) 的结果上. 6 然而, 类的构造过程可以用户定义 - 在定义类的时候通过传入一个 metaclass 关键字; 7 或者通过继承至一个有 metaclass 关键字的父类. 8 如, 9 class Meta(type): 10 pass 11 12 class MyClass(metaclass=Meta): 13 pass 14 or 15 class MySubclass(MyClass): 16 pass 17 18 在 class 定义中的其他关键字参数会被传给所有 metaclass 的操作. 19 当 class 构造体被执行的时候,python 解释器按照下列顺序 interpretation, 20 确定 class 对应的 metaclass , 21 准备 class 的 namespace, 22 执行 class 定义体 - class body, 23 创建 class 对象 - class object. 24 25 26 下面我们逐一详细看一下儿以上几个解释步骤, 27 metaclass 的确定 - Determining the appropriate metaclass 28 metaclass 确定原则, 以 class B(metaclass = A, C) 为例阐述, 29 如果 class 的定义中没有指定基类 bases, 并且没有 metaclass 关键字,采用 type() 作为 metaclass. 30 如果有关键字 metaclass = A, 并且 A 不是 type() 的实例, 直接采用 A 作为 metaclass. 31 如果 A 是 type() 一个实例 instance, 或者有定义基类 bases, 则 采用 the most derived metaclass 32 33 注, 34 candidate metaclasses 有2部分原来: 35 a, metaclass 关键字, 如上例子中的 A 36 b, 所有基类 bases的 metaclasses, 如上例子中的 type(c) 37 the most derived metaclass 是 candidate metaclasses 集合中的一个, 38 它需要满足是所有其他的 candidate 的 subtype,如果没有任何一个 candidate 满足这个条件, 39 则 class 的定义会报错,raise TypeError exception. 40 41 namespace 的确定 - Preparing the class namespace 42 metaclass 确定了之后, 到了该确定 namespace 的时候. 43 如果 metaclass 有 __prepare__ attribute, 下面的语句将被调用,以确定 namespace 44 namespace = metaclass.__prepare__(name, bases, **kwds), 45 **kwds 来至于 class 的定义语句. 46 若 metaclass 没有 __prepare__ attribute, 则 类的 namespace 被初始化为空 an empty ordered mapping. 47 48 class body 的执行 - Executing the class body 49 class body 的执行, 可以用如下伪代码来表示, 50 exec(body, globals(), namespace) 51 52 跟一般的对 exec()的调用的关键区别在于, 当 class 定义在一个函数中时候, 53 允许类的定义体 class body (包括其中的方法) 引用 '当前' 和 '外层' 作用域 scope 的 names 54 "The key difference from a normal call to exec() is that lexical scoping allows 55 the class body (including any methods) to reference names from the current and 56 outer scopes when the class definition occurs inside a function." 57 然而,及时 class 被定义在一个函数中, 在 class scope 所定义的 names 对 class 中定义的 methods 58 仍然不可见. 59 对类变量 Class variables 的访问, 必须通过 self.variable 的形式访问,或作为第一个参数传入. 60 即, 61 class A(object): 62 a = "variable - a" 63 64 def func1(self): # 必须通过 self.variable 的形式访问 Class variables 65 print(self.a) 66 67 def func2(self, a): # 作为第一个参数传入的形式访问 Class variables 68 print(a) 69 70 再或者通过 隐式词法作用于 implicit lexically scoped __class__ 引用, 见下一节描述. 71 72 class object 的创建 - Creating the class object 73 class namespace 被确定之后, class object 由下面方法创建, 74 metaclass(name, bases, namespace, **kwds) 75 **kwds 跟传给 __prepare__ 的 **kwds, 即来至于 class 的定义语句. 76 77 class object 即 super().__class__, 是一个在 class boby 中存在引用 __class__ 或 super 的方法 78 的情况下儿被编译器 compiler 创建一个隐式闭包引用 an implicit closure reference. 79 这保证了通过把 class 或者 instance 作为第一个参数来调用(属性/方法)的时候,无参数的 super() 80 可以正确的识别对应的 class, 即 class body 中的 self 机制. 81 82 CPython implementation detail: 83 从 python 3.6 开始, __class__ 被传给 metaclass 作为 __classcell__ 存储在类的 namespace 中. 84 如果 __class__ 存在, 需要向上反推到 type.__new__ 的调用,以保证 class 的正确初始化. 85 如果 type.__new__ 调用失败,将报告 DeprecationWarning, 之后报 RuntimeWarning (python 3.6). 86 当采用默认 metaclass, 或某一 metaclass 调用了 type.__new__, 在创建了 class object 下面额外 87 的步骤姜维调用, 88 a, type.__new__ 收集 class namespace 中的所有 descriptors, 定义 __set_name__() 方法 89 b, 在所定义的类上调用 __set_name__ 中的描述符方法, 90 class being defined and the assigned name of that particular descriptor 作为参数. 91 c, 在被定义 class 的最近的基类上(MRO)调用 __init_subclass__(), 92 当 class object 被创建后, 如果 class 存在 decorators 将 class object 传给 decorators 装饰. 93 将返回的新对象绑定到 local namespace. 94 当一个新的 class 是由 type.__new__ 创建的, namespace parameter 复制一个新的 ordered mapping 95 中, 源对象被弃用. 新的 ordered mapping 将被包装成 read-only proxy, 最终成为 class object 的 96 __dict__ 属性. 97 98 最后来看例子 - Metaclass example 99 metaclasses 的潜在用途有很多, 包括 enum, logging, interface checking, automatic delegation, 100 automatic property creation, proxies, frameworks, and automatic resource locking/synchronization. 101 102 下面是一个通过 collections.OrderedDict 来记录类参数定义顺序的 metaclasses 应用的例子, 103 import collections 104 class OrderedClass(type): 105 106 @classmethod 107 def __prepare__(metacls, name, bases, **kwds): 108 return collections.OrderedDict() 109 110 def __new__(cls, name, bases, namespace, **kwds): 111 result = type.__new__(cls, name, bases, dict(namespace)) 112 result.members = tuple(namespace) 113 return result 114 115 class A(metaclass=OrderedClass): 116 A = 1 117 C = 2 118 B = 3 119 def one(self): pass 120 def two(self): pass 121 def three(self): pass 122 def four(self): pass 123 Output, 124 >>> A.members 125 ('__module__', '__qualname__', 'A', 'C', 'B', 'one', 'two', 'three', 'four') 126 127 当类 A 的定义体被执行的时候, 先调用 metaclass 的 __prepare__ 方法, __prepare__() 128 返回一个空的 collections.OrderedDict. 这个 OrderedDict 被用来按声明顺序记录 A 中 129 定义的 methods and attributes. 当解释器解释到 attributes 被声明的位置时, 通过执行声明 130 将 attributes 被添加到 ordered dictionary. 并且调用 metaclass 的 __new__() method 被, 131 结果就是 __new__() 创建一个新的的 type 并将 ordered dictionary 的 keys 存储在 members 132 属性中. 133 134 Reference, 135 python doc, 136 https://docs.python.org/3/reference/datamodel.html#metaclasses