社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
python中定义一个类允许继承自多个父类,各父类之间可能从在父子关系或兄弟关系。
兄弟关系指有共同的父类
so....
对于子类中的属性及方法到底继承自哪个父类了?
那么就让我们来掌握python中的 MRO(Method Resolution Order):方法解析顺序。
先上结论:
1. python2.2以前的版本 经典类时代,采用DFS(深度优先搜索(子节点顺序:从左到右))
2. python2.2新式类诞生, 经典类DFS, 新式类BFS (广度优先搜索) 类名称.__mro__可以查看MRO
存在的问题: DFS: 只能继承无法重写 单调性 BFS:单调性
3. python2.3开始新式类用C3算法。
4. python3开始全部用新式类,当然就是C3算法。
经典类:一种没有继承的类,实例类型都是type类型,如果经典类被作为父类,子类调用父类的构造函数时会出错
经典类的MRO(DFS) python3及以前均存在。且均为DFS深度优先
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
棱形继承模式下:存在公共父类(D)的多继承,这种情况下DFS必定经过公共父类(D),假使公共父类(D)有一些属性或方法,但是子类(C)又重写了这些属性或者方法,那么按照DFS顺序必定是会先找到D的属性或方法,那么C的属性或者方法将永远访问不到。
存在的问题:棱形继承模式下出现子类只能继承无法重写的现象。 (所以新式类不会采用DFS)
python2.2新式类MRO(BFS)广度优先
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
优缺点分析:
正常继承模式,看起来正常,不过实际上感觉很别扭,比如B明明继承了D的某个属性(假设为foo),C中也实现了这个属性foo,那么BFS明明先访问B然后再去访问C,但是为什么foo这个属性会是C?这种应该先从B和B的父类开始找的顺序,我们称之为单调性。
第二种,棱形继承模式,这种模式下面,BFS的查找顺序虽然解了DFS顺序下面的棱形问题,但是它也是违背了查找的单调性。
存在的问题:虽然解决DFS棱形模式的只继承不能复写的问题,但引入了不符合单调性的问题。
因为违背了单调性,所以BFS方法只在Python2.2中出现了,在其后版本中用C3算法取代了BFS。
python2.3及以后新式类MRO(C3算法)
C3算法解决了单调性问题和只能继承无法重写问题,上面代码段中的例子在python2.3及以后执行,MRO如下
C3算法详解:
L[C(B1 ... BN)] = C + merge(L[B1] ... L[BN], B1 ... BN)
So in our case L[F(A, B)] = F + merge(L[A], L[B], A, B)
一个列表【C1, C2......CN】的头及尾计算:
head(C1C2⋯CN)=C1head(C1C2⋯CN)=C1tail(C1C2⋯CN)=C2C3⋯CN
C3线性化步骤:
1. 选取merge中的第一个列表记为当前列表 K。
2. 从列表K中拿出第一个元素,如果该元素在其他列表的tail(或者不出现)中则将该元素移入类C的线性化列表中。将其从merge的每一个列表中移出。
3. 否则设置K为merge中的下一个列表,重复步骤2.
4.如果 merge 中所有的类都被移除,则输出类创建成功;如果不能找到下一个 h,则输出拒绝创建类 C并抛出异常。
通过C3线性化分析以上两种模式的MRO.
L[A(B,C)]=A + merger(L[B],L[C],B,C)
L[B]=L[B(D)]=B+D
L[C]=L[C(E)]=C+E
L[A(B,C)] = A+ merger(B+D,C+E,B,C)
最终MRO列表为L[A]
1. L[A]=【A】+ merger(B+D,C+E,B,C)
2. 判断B+D 第一个元素为B 在 其他列表 C+E B C中都不不在tail(X)中, 所以加入B L[A]=[A,B]+ merger(D,C+E,C)
3. merger(D,C+E,C), 拿出D, L[A]=[A,B,D]+ merger(C+E,C)
4. merger(C+E,C) 拿出C, L[A]=[A,B,D,C]+ merger(E)
5. L[A]=[A,B,D,C,E]
分析下图中的MRO
L[E] = [E,object]
L[D] = [D,object]
L[F] ] [F,object]
L[B] = B +merge(L[E],L[D],E,D)
L[B] = B+merge([E,object],[D,object】,E,D)
L[B] = [B,E,D,object]
L[C] = [C,D,F,object]
L[A] = A+merge(L[B],L[C],B,C)
L[A] = A+merge([B,E,D,object],[C,D,F,object], B, C)
L[A]= 【A,B】+ merge([E,D,object],[C,D,F,object], C)
L[A]= 【A,B,E】+ merge([D,object],[C,D,F,object], C)
L[A]= 【A,B,E,C】+ merge([D,object],[D,F,object]) # 注意从上一行到这一行,先选择D但不符合条件,然后选择C
# L[A]= 【A,B,E,C】+ merge([D,object],[D,F,object]) #注意这里,当两个D都在首位置的时候,也移除D
#L[A]= 【A,B,E,C】+ merge([D,object],[D,F,object],[G,object]) # 如果是这样移除F,G,然后是
L[A]= 【A,B,E,C,D】+ merge([object],[F,object])
L[A]= 【A,B,E,C,D,F】+ merge([object],[object]) #注意从上一行到这一行,没选择object
L[A]= 【A,B,E,C,D,F,object】
所以类A的MRO 为 【A,B,E,C,D,F,object】
掌握MRO了吗?
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!