C3算法规则
-- 每一个类的继承顺序都是从基类向子类看-- 形成一个指向关系的顺序[当前类] + [父类的继承顺序]-- 进行一个提取-- 如果一个类出现从左到右的第一个顺序上,并且没有出现在后面的顺序中,或者出现在后面顺序了,但是仍然是第一个,那么就把这个类提取出来
示例1
# class A(object): ...# class B(A): ...# class C(A): ...# class D(B, C): ...# print(D.__mro__) # (, , , , )'''手推mro,从上至下的顺序L(A) = [A] + [O]A = [0]A0 = []L(A) = AOL(B) = [B] + [A0]B = [AO]BA = [O]BAO = []L(B) = BAOL(C) = [C] + [AO]C = [AO]CA = [0]CAO = []L(C) = CAOL(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 (, , , , , , , )'''手推C3算法L(G) = [G] + [O]G = [O]GO = []L(G) = GOL(E) = [E] + [G0]E = [GO]EG = [O]EGO = []L(E) = EGOL(D) = [D] + [DO]D = [O]DO = []L(D) = DOL(F) = [F] + [FO]F = [O]FO = []L(F) = FOL(B) = [B] + [DO] + [EGO]B = [DO] + [EGO]BD = [O] + [EGO]BDE = [O] + [GO]BDEG = [O] + [O]BDEGO = []L(B) = BDEGOL(C) = [C] + [DO] + [FO]C = [DO] + [FO]CD = [O] + [FO]CDF = [O] + [O]CDFO = []L(C) = CDFOL(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 (, , , , , , )33 # 打印结果如下示例34 '''35 enter F36 enter E37 enter B38 leave B39 enter C40 enter D41 enter A42 leave A43 leave D44 leave C45 leave E46 enter D47 enter A48 leave A49 leave D50 leave F51 '''
解:
首先观察代码,画出继承顺序图
那么这里为什么要用到c3算法,就是为了算出mro顺序(这里只能手推,不能打印)。当算出来mro顺序之后,我们就可以在后面用到了。
'''L(A) = [A] + [O]A = [0]AO = []L(A) = AOL(B) = [B] + [O]B = [O]BO = []L(B) = BOL(C) = [C] + [AO]C = [AO]CA = [O]CAO = []L(C) = CAOL(D) = [D] + [AO]D = [AO]DA = [O]DAO = []L(D) = DAOL(E) = [E] + [BO] + [CAO]E = [BO] + [CAO]EB = [O] + [CAO]EBC = [O] + [AO]EBCA = [O] + [O]EBCAO = []L(E) = EBCAOL(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的继承顺序,放这里:FEBCDAO1. 代码从第F()开始执行,执行其内部的init方法首先打印enter F2. 执行E中的init方法,打印一行enter E3. 执行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 Fenter Eenter Bleave Benter Center Denter Aleave Aleave Dleave Cleave Eenter Denter Aleave Aleave Dleave F'''
that's all