首页 > 技术文章 > python面向对象进阶-04菱形继承问题

suren-apan 2019-09-21 10:54 原文

类的分类

新式类

继承了object的类以及该类的子类,都是新式类
Python3中所有的类都是新式类

经典类

没有继承object的类以及该类的子类,都是经典类
只有Python2中才有经典类

菱形继承问题

如果继承关系为菱形结构,即子类的父类最后继承了同一个类,那么属性的查找方式有两种:

经典类下:深度优先
广度优先:广度优先

经典类:一条路走到黑,深度优先
新式类:不找多各类最后继承的同一个类,直接去找下一个父类,广度优先
个人偏向下面的这个理解

当出现了菱形继承时,新式类,先深度,当遇到了共同父类时就广度

而经典类,就是深度优先

当类是经典类时,多继承情况下,在要查找属性不存在时,会按照深度优先的方式查找下去
当类是新式类时,多继承情况下,在要查找属性不存在时,会按照广度优先的方式查找下去

不废话, 上例子!!!

class G(object):
    da
    #     print('from G')
    pass

print(G.__bases__)

class E(G):
    da
    #     print('from E')
    pass

class B(E):
    da
    #     print('from B')
    pass

class F(G):
    da
    #     print('from F')
    pass

class C(F):
    da
    #     print('from C')
    pass

class D(G):
    da
    #     print('from D')
    pass

class A(B, C, D):
    def test(self):
        print('from A')

obj = A()
(<class 'object'>,)
obj.test()  # A->B->E-C-F-D->G-object

mro()方法介绍

python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,如:

print(A.mro())  # A.__mro__

for i in A.mro():
    print(i)

[<class 'main.A'>, <class 'main.B'>, <class 'main.E'>, <class 'main.C'>, <class 'main.F'>, <class 'main.D'>, <class 'main.G'>, <class 'object'>]
<class 'main.A'>
<class 'main.B'>
<class 'main.E'>
<class 'main.C'>
<class 'main.F'>
<class 'main.D'>
<class 'main.G'>
<class 'object'>

为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
子类会先于父类被检查
多个父类会根据它们在列表中的顺序被检查
如果对下一个类存在两个合法的选择,选择第一个父类

推荐阅读