一窥Python中MRO排序原理

南楼画角 提交于 2019-11-29 08:16:59

在 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

对比系统打印出的结果,顺序是一致的。这样下次你就可以装逼地手动计算多继承时调用类的顺序了 (好像没啥卵用~)

作者:大白杏仁
链接:https://www.jianshu.com/p/6651ed35104c
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!