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