C3算法规则
-- 每一个类的继承顺序都是从基类向子类看
-- 形成一个指向关系的顺序[当前类] + [父类的继承顺序]
-- 进行一个提取
-- 如果一个类出现从左到右的第一个顺序上,并且没有出现在后面的顺序中,或者出现在后面顺序了,但是仍然是第一个,那么就把这个类提取出来
示例1
# class A(object): ...
# class B(A): ...
# class C(A): ...
# class D(B, C): ...
# print(D.__mro__) # (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
'''手推mro,从上至下的顺序
L(A) = [A] + [O]
A = [0]
A0 = []
L(A) = AO
L(B) = [B] + [A0]
B = [AO]
BA = [O]
BAO = []
L(B) = BAO
L(C) = [C] + [AO]
C = [AO]
CA = [0]
CAO = []
L(C) = CAO
L(D) = [D] + [BAO] + [CAO]
D = [BAO] + [CAO]
DB = [AO] + [CAO]
DBC = [AO] + [AO]
DBCA = [O] + [O]
DBCAO = []
L(D) = DBCA0
'''
示例2
# class G(object): ...
# class E(G): ...
# class D(object): ...
# class F(object): ...
# class B(D, E): ...
# class C(D, F): ...
# class A(B, C): ...
# print(A.__mro__) # ABCDEGFO (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.E'>, <class '__main__.G'>, <class '__main__.F'>, <class 'object'>)
'''手推C3算法
L(G) = [G] + [O]
G = [O]
GO = []
L(G) = GO
L(E) = [E] + [G0]
E = [GO]
EG = [O]
EGO = []
L(E) = EGO
L(D) = [D] + [DO]
D = [O]
DO = []
L(D) = DO
L(F) = [F] + [FO]
F = [O]
FO = []
L(F) = FO
L(B) = [B] + [DO] + [EGO]
B = [DO] + [EGO]
BD = [O] + [EGO]
BDE = [O] + [GO]
BDEG = [O] + [O]
BDEGO = []
L(B) = BDEGO
L(C) = [C] + [DO] + [FO]
C = [DO] + [FO]
CD = [O] + [FO]
CDF = [O] + [O]
CDFO = []
L(C) = CDFO
L(A) = [A] + [BDEGO] + [CDFO]
A = [BDEGO] + [CDFO]
AB = [DEGO] + [CDFO]
ABC = [DEGO] + [DFO]
ABCD = [EGO] + [FO]
ABCDE = [GO] + [FO]
ABCDEG = [O] + [FO]
ABCDEGF = [O] + [O]
ABCDEGFO = []
L(A) = ABCDEGFO
'''
应用
看代码,请说出执行流程
1 class A(object): 2 def __init__(self): 3 print("enter A") 4 print("leave A") 5 class B(object): 6 def __init__(self): 7 print("enter B") 8 print("leave B") 9 class C(A): 10 def __init__(self): 11 print("enter C") 12 super().__init__() 13 print("leave C") 14 class D(A): 15 def __init__(self): 16 print("enter D") 17 super().__init__() 18 print("leave D") 19 class E(B, C): 20 def __init__(self): 21 print("enter E") 22 B.__init__(self) 23 C.__init__(self) 24 print("leave E") 25 class F(E, D): 26 def __init__(self): 27 print("enter F") 28 E.__init__(self) 29 D.__init__(self) 30 print("leave F") 31 F() 32 # print(F.__mro__) # FEBCDA0 (<class '__main__.F'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>) 33 # 打印结果如下示例 34 ''' 35 enter F 36 enter E 37 enter B 38 leave B 39 enter C 40 enter D 41 enter A 42 leave A 43 leave D 44 leave C 45 leave E 46 enter D 47 enter A 48 leave A 49 leave D 50 leave F 51 '''
解:
首先观察代码,画出继承顺序图
那么这里为什么要用到c3算法,就是为了算出mro顺序(这里只能手推,不能打印)。当算出来mro顺序之后,我们就可以在后面用到了。
''' L(A) = [A] + [O] A = [0] AO = [] L(A) = AO L(B) = [B] + [O] B = [O] BO = [] L(B) = BO L(C) = [C] + [AO] C = [AO] CA = [O] CAO = [] L(C) = CAO L(D) = [D] + [AO] D = [AO] DA = [O] DAO = [] L(D) = DAO L(E) = [E] + [BO] + [CAO] E = [BO] + [CAO] EB = [O] + [CAO] EBC = [O] + [AO] EBCA = [O] + [O] EBCAO = [] L(E) = EBCAO L(F) = [F] + [EBCAO] + [DAO] F = [EBCAO] + [DAO] FE = [BCAO] + [DAO] FEB = [CAO] + [DAO] FEBC = [AO] + [DAO] FEBCD = [AO] + [AO] FEBCDA = [O] + [O] FEBCDAO = [] L(F) = FEBCDAO '''
一番推算,mro的顺序为FEBCDAO。
接下来,我们开始解释代码的执行流程。
'''
先把mro的继承顺序,放这里:FEBCDAO
1. 代码从第F()开始执行,执行其内部的init方法首先打印enter F
2. 执行E中的init方法,打印一行enter E
3. 执行B中的init方法,打印enter B,紧接着打印leave B,执行完毕,代码回到E中
4. 执行C中的init方法,打印enter C, 然后调用父类的super方法,
那该执行父类的init方法,这里要知道C的父类是谁?是A吗?(注意,关键点来了)
不是!而是顺着mro的顺序查找,C后面是D,所以,执行D的init方法
首先打印enter D, 接着D又执行super方法,找父类的super方法,mro中是A
所以执行A中的init方法,打印enter A,在打印leave A,然后,回到D中
又打印leave D,执行完毕,回到C中
打印leave C,执行完毕,回到E中
打印leave E,E此时也执行完毕,回到最开始的F中
5. 执行D中init方法
首先打印enter D
调用父类的super方法,从mro找父类
打印enter A
打印leave A
A执行完毕,回到D中
打印leave D
执行完毕,回到最初F中
6. 打印leave F,程序结束
enter F
enter E
enter B
leave B
enter C
enter D
enter A
leave A
leave D
leave C
leave E
enter D
enter A
leave A
leave D
leave F
'''
that's all