Python高级编程(11):类和实例属性的查找顺序—mro查找
我们先来看一段代码:
1 |
|
上面的运行结果是没有任何疑问的,那么我们为啥要专门说明一下这个类和实例的查找顺序呢?那是因为在多继承的条件之下,我们的继承关系就比较复杂了,一眼直接看出来就比较难了。
MRO算法
MRO就是method resolution order,主要用于在多继承时判断所调用属性的路径(来自于哪个类)
经典类
在Python2.2之前,我们Python里面的类称为经典类,经典类是一种没有继承的类,实例类型都是type类型,如果经典类被作为父类,子类调用父类的构造函数时会出错。这时MRO的方法为DFS(深度优先搜索(子节点顺序:从左到右))
在上面的图里面就是:A–>B–>D–>C–>E。也就是说会先往一条路深了查找,如果找不到就走另一条路。按照这种情况其实是非常合理的,B里面找不到我们就去查找它的父类D,但是我们来看下面的情况:
按照之前的分析就应该是:A–>B–>D–>C,可是假如我们C里面重写了D的方法,我们还按照之前的深度优先算法的话,那么C有可能就起不到我们想要的作用了。所以深度优先对于菱形继承就有问题了。
新式类
在Python2.2之后,新式类就诞生了。新式类的每个类都继承于一个基类,可以是自定义类或者其它类,默认会继承object类。子类可以调用父类的构造函数。然后就引入了(广度优先搜索(子节点顺序:从左到右))
按照广度优先搜索的原则就应该是:A–>B–>C–>D,这样其实很合理的,把与B同级的C也搜索完,我们才去搜索D。同样还是有一个问题:
按照广度优先搜索的原则就应该是:A–>B–>C–>D–E,可是假如我们BCD三者都有一个共同的方法,我们先去B里面查找,发现没有就去C里面查找,可是因为B已经继承了D,所以应该把BD当做一个整体,这样C就会覆盖掉D里面的方法,所以广度优先搜索就显得不够用了,所以说这个广度优先搜索在Python2.3之后就被取代了。
这样,从Python2.3开始一直到现在,Python采用的就是C3算法了,关于C3算法网上有很多文章,这里贴几篇文章:你真的理解Python中MRO算法吗?,python多重继承C3算法。
我们先来解决这个菱形继承模式:
1 | class D: |
这实际上就是采用了广度优先的算法,我们接下来再来解决正常继承模式:
1 |
|
这实际上就是采用了深度优先的算法。
[ - ]参考文章:python类学习以及mro–多继承属性查找机制.