在 Python 中用到多继承时,调用父类方法很容易出错:父类方法调用了多次,只能通过__mro__
魔法方法来获取调用顺序,花了点时间了解其中涉及的排序算法,顺带记录
1. 拓扑排序
在了解 MRO 排序算法之前,先了解下拓扑排序(以下摘自维基百科)
在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,称为该图的一个拓扑排序(英语:Topological sorting)。
1.每个顶点出现且只出现一次;
2.若A在序列中排在B的前面,则在图中不存在从B到A的路径。
说人话,看下面的图就明白了 (图片搬运自别人的博客,画的很不错我直接拿来用了,链接在文章末尾),图中每个点都是有指向性的:可能指向别人或者被别人指向。
拓扑顺序就是:每次找到一个只指向别人的点 (学术性说法:入度为0),记录下来;然后忽略掉这个点和它所指出去的线,再找到下一个只指向别人的点,记录下来,直到剩最后一个点,所有记录的点的顺序就是拓扑顺序
上图中,只有点1
只指向别人,输出1;去掉点1
和它伸出的两根线外只有点2
只指向别人,输出2;...类推下去,得到拓扑排序结构: 1 2 4 3 5
2. MRO 排序算法
- MRO 排序应用了 C3 算法,想了解 C3 自己查吧...总之得到的结果类似于拓扑排序,下面有段简单的多继承代码和其对应的拓扑排序的抽象图 (所用代码实例和图片均来应用自别处,文章末尾有链接)
class D(object):
pass
class E(object):
pass
class F(object):
pass
class C(D, F):
pass
class B(E, D):
pass
class A(B, C):
pass
if __name__ == '__main__':
print A.__mro__
得到的输出结果:
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>, <type 'object'>)
-
下面就是抽象出来的图
我们就用拓扑排序来分析,但是这里会碰到同时存在好几个点都是入度为0 (说人话,就是没有被别人指向的点),这时按照树的排序来,即从左到右,从根到叶,这里 A 就是根。
所以具体情况就是:我们先找到了点 A只有它没有被别人指向,输出A
;去掉A及其伸出的两条线,剩 B 和 C 点同时满足只指向别人,按照树的顺序从左到右,故先输出B
;去掉线剩 E 和 C ,输出E
;去线剩 C,输出C
;去线剩 D 和 F ,输出D
;去线只剩F ,输出F
;最后输出object
;得到的输出结果:
A B E C D F object
对比系统打印出的结果,顺序是一致的。这样下次你就可以装逼地手动计算多继承时调用类的顺序了 (好像没啥卵用~)