MRO的计算(C3算法及应用)
在程序中出现了多个类的继承而且出现了菱形继承,并且又要用到super,知道MRO就显得极为重要,我们使用C3算法来计算MRO
下面通过例子来解释:
class A: pass class B(A): pass class C(A): pass class D(B,C): pass class E(C,A): pass class F(D,E): pass class N: pass class O: pass class M(N,O): pass class G(E,M): pass class H(G,F): pass
我们来计算上述代码的MRO
1.首先把继承树图画出来
是这样子的(不太好看,凑合一下)
2.假设C3算法是一个函数式,继承代表相加,然后把函数式写出来,很简单,看着继承树图写,不过顺序要与代码中继承的顺序相同
L(A) = A
L(B) = B + L(A)
L(C) = C + L(A)
L(D) = D + L(B) + L(C)
L(E) = E + L(C) + L(A)
L(F) = F + L(D) + L(E)
L(M) = M + L(N) + L(O)
L(G) = G + L(E) + L(M)
L(H) = H + L(G) + L(F)
3.函数式写出来了,下来我们进行化简
L(A) = A
L(B) = B + L(A) = BA
L(C) = C + L(A) = CA
L(D) = D + L(B) + L(C) = D + BA + CA =DBCA
L(E) = E + L(C) + L(A) = E + CA + A = ECA
L(F) = F + L(D) + L(E) = F + DBCA + ECA = FDBECA
L(M) = M + L(N) + L(O) = M + N + O =MNO
L(G) = G + L(E) + L(M) = G + ECA + MNO = GECAMNO
L(H) = H + L(G) + L(F) = H + GECAMNO + FDBECA = HGFDBECAMNO
函数式中的+代表的是merge(),merge规则:
1. 如果第一个序列的第一个元素,是后续序列的第一个元素,或者不再后续序列中再次出现,则将这个元素合并到最终的方法解析顺序序列中,并从当前操作的全部序列中删除。
2. 如果不符合,则跳过此元素,查找下一个列表的第一个元素,重复1的判断规则
最后我们可以来验证
print(H.__mro__)
发现顺序与我们算的顺序相同,只不过后边多了个class object,因为我们所有的类都要继承obj,所以也不足为奇
我们计算MRO就是要为super做铺垫,所以我们来看一道面试题
class Init(object): def __init__(self,v): print("init") self.val = v class Add2(Init): def __init__(self,val): print("Add2") super(Add2,self).__init__(val) print(self.val) self.val += 2 class Mult(Init): def __init__(self,val): print("Mult") super(Mult, self).__init__(val) self.val *= 5 class HaHa(Init): def __init__(self,val): print("HaHa") super(HaHa,self).__init__(val) self.val /= 5 class Pro(Add2,Mult,HaHa): pass class Incr(Pro): def __init__(self,val): super(Incr,self).__init__(val) self.val += 1 p = Incr(5) print(p.val)
大致看一眼,发现出现了多个继承,还涉及到了super的用法,按照方法一步一步来
1.画继承树图
2.然后算出MRO:Incr,Pro,Add,Mult,Haha,Init,(Object)
3.super是访问MRO中下一个类的内容,秉持着这个原则我们进行稍加分析,这道题只不过是几个super的叠用,答案不难算出来