分析不同类的 MRO
- A: A->X->Y->object
- B: B->Y->X->object
- C: C->A->B->X->Y->object
很明显,B、C 中间的 X、Y 顺序是相反的,就是说 B 被继承时,它的搜索顺序会被改变
在 python2 中运行这段代码的报错
在 python3 中运行这段代码的报错
C3 MRO 算法
- 为解决前面两个算法的问题,Python 2.3 采用了 C3 方法来确定方法搜索顺序
- 多数情况下,如果别人提到 Python 中的 MRO,指的都是 C3 算法
将上面第一个栗子的代码放到 python3 中运行
class A: def test(self): print("CommonA") class B(A): pass class C(A): def test(self): print("CommonC") class D(B, C): pass D().test() # 输出结果 CommonC
简单了解下 C3 算法
以上面代码为栗子,C3 会把各个类的 MRO 等价为以下等式
- A:L[A] = merge(A , object)
- B:L[B] = B + merge(L[A] , A)
- C:L[C] = C + merge(L[A] , A)
- D:L[D] = D + merge(L[B] , L[C] , B , C)
了解一下:头、尾
以 A 类为栗,merge() 包含的 A 成为 L[A] 的头,剩余元素(这里只有 object)称为尾
merge 的运算方式
- 将 merge 第一个列表的头元素(如 L[A] 的头),记作 H
- 如果 H 出现在 merge 其他列表的头部,则将其输出,并将其从所有列表中删除
- 如果 H 只出现一次,那么也将其输出,并将其从所有列表中删除
- 如果 H 出现在 merge 其他列表的非头部,则取下一个列表的头元素记作 H,然后回到步骤二
- 最后回到步骤一,重复以上步骤
重复以上步骤直到列表为空,则算法结束;如果不能再找出可以输出的元素,则抛出异常
简单类 MRO 的计算栗子
class B(object): pass print(B.__mro__) (<class '__main__.B'>, <class 'object'>)
MRO 计算方式
L[B] = L[B(object)] = B + merge(L[object]) = B + L[object] = B object
单继承 MRO 的计算栗子
# 计算 MRO class B(object): pass class C(B): pass print(C.__mro__) (<class '__main__.C'>, <class '__main__.B'>, <class 'object'>)
MRO 计算方式
L[C] = C + merge(L[B])
= C + L[B]
= C B object
多继承 MRO 的计算栗子
O = object class F(O): pass class E(O): pass class D(O): pass class C(D, F): pass class B(D, E): pass class A(B, C): pass print(C.__mro__) print(B.__mro__) print(A.__mro__) # 输出结果 (<class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>, <class 'object'>) (<class '__main__.B'>, <class '__main__.D'>, <class '__main__.E'>, <class 'object'>) (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.E'>, <class '__main__.F'>, <class 'object'>)
O 类、object 类 MRO 计算
L[O] = O = object
D、E、F 类 MRO 计算
L[D] = D + merge(L[O])
= D O
C 类 MRO 计算
L[C] = L[C(D, F)] = C + merge(L[D], L[F], DF) # 从前面可知 L[D] 和 L[F] 的结果 = C + merge(DO, FO, DF) # 因为 D 是顺序第一个并且在几个包含 D 的 list 中是 head, # 所以这一次取 D 同时从列表中删除 D = C + D + merge(O, FO, F) # 因为 O 虽然是顺序第一个但在其他 list (FO)中是在尾部, 跳过 # 改为检查第二个list FO # F 是第二个 list 和其他 list 的 head # 取 F 同时从列表中删除 F = C + D + F + merge(O) = C D F O
B 类 MRO 计算
L[B] = L[B(D, E)] = B + merge(L[D], L[E], DE) = B + merge(DO, EO, DE) = B + D + merge(O, EO, E) = B + D + E + merge(O) = B D E O
A 类 MRO 计算
L[A] = L[A(B,C)] = A + merge(L[B], L[C], BC) = A + merge( BDEO, CDFO, BC ) = A + B + merge( DEO, CDFO, C ) # D 在其他列表 CDFO 不是 head,所以跳过到下一个列表的 头元素 C = A + B + C + merge( DEO, DFO ) = A + B + C + D + merge( EO, FO ) = A + B + C + D + E + merge( O, FO ) = A + B + C + D + E + F + merge( O ) = A B C D E F O
多继承 MRO 的计算栗子二
O = object class F(O): pass class E(O): pass class D(O): pass class C(D, F): pass class B(E, D): pass class A(B, C): pass print(C.__mro__) print(B.__mro__) print(A.__mro__) # 输出结果 (<class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>, <class 'object'>) (<class '__main__.B'>, <class '__main__.E'>, <class '__main__.D'>, <class 'object'>) (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>, <class 'object'>)
O 类、object 类 MRO 计算
L[O] = O = object
D、E、F 类 MRO 计算
L[D] = D + merge(L[O])
= D O
C 类 MRO 计算
L[C] = L[C(D, F)]
= C + merge(L[D], L[F], DF)
= C + merge(DO, FO, DF)
= C + D + merge(O, FO, F)
= C + D + F + merge(O)
= C D F O
B 类 MRO 计算
L[B] = L[B(E, D)]
= B + merge(L[E], L[D], ED)
= B + merge(EO, DO, ED)
= B + E + merge(O, DO, D)
= B + E + D + merge(O)
= B E D O
A 类 MRO 计算
L[A] = L[A(B, C)] = A + merge(L[B], L[C], BC) = A + merge(BEDO, CDFO, BC) = A + B + merge(EDO, CDFO, C) = A + B + E + merge(DO,CDFO, C) = A + B + E + C + merge(O,DFO) = A + B + E + C + D + merge(O, FO) = A + B + E + C + D + F + merge(O) = A B E C D F O