Python正课74 —— 多继承带来的菱形问题

本文内容皆为作者原创,如需转载,请注明出处:https://www.cnblogs.com/xuexianqi/p/12669925.html

一:菱形问题

  大多数面向对象语言都不支持多继承,而在Python中,一个子类是可以同时继承多个父类的,这固然可以带来一个子类可以对多个不同父类加以重用的好处,但也有可能引发著名的 Diamond problem菱形问题(或称钻石问题,有时候也被称为“死亡钻石”),菱形其实就是对下面这种继承结构的形象比喻。

LXWTT

class A(object):
    def test(self):
        print('from A')
    pass


class B(A):
    def test(self):
        print('from B')
    pass


class C(A):
    def test(self):
        print('from C')
    pass


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


# print(D.mro())  # 类D以及类D的对象访问属性都是参照该类的mro列表
# 输出:[<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]

obj = D()
obj.test()        # from C

print(D.test)       # <function C.test at 0x039D84A8>

print(C.mro())  # 类C以及类C的对象访问属性都是参照该类的mro列表
# 输出:[<class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

c = C()
c.test()        # from C

总结:类相关的属性查找(类名.属性,该类的对象.属性),都是参照该类的mro

python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。 而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:

1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类

二:如果多继承是非菱形继承,经典类与新式的属性查找顺序一样:

都是一个分支一个分支地找下去,然后最后找object

class E:
    # def test(self):
    #     print('from E')
    pass


class F:
    def test(self):
        print('from F')


class B(E):
    # def test(self):
    #     print('from B')
    pass


class C(F):
    # def test(self):
    #     print('from C')
    pass


class D:
    def test(self):
        print('from D')


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


# 新式类
# print(A.mro()) # A->B->E->C->F->D->object

obj = A()
obj.test()  # 结果为:from F

三:如果多继承是菱形继承,经典类与新式类的属性查找顺序不一样:

经典类:深度优先,会在检索第一条分支的时候就直接一条道走到黑,即会检索大脑袋(共同的父类)

新式类:广度优先,会在检索最后一条分支的时候检索大脑袋

class G:  # 在python2中,未继承object的类及其子类,都是经典类
    # def test(self):
    #     print('from G')
    pass


class E(G):
    # def test(self):
    #     print('from E')
    pass


class F(G):
    def test(self):
        print('from F')


class B(E):
    # def test(self):
    #     print('from B')
    pass


class C(F):
    def test(self):
        print('from C')


class D(G):
    def test(self):
        print('from D')


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


# 新式类
# print(A.mro()) # A->B->E->C->F->D->G->object

# 经典类:A->B->E->G->C->F->D
obj = A()
obj.test()  #

四:总结:

多继承到底要不用???

要用,但是规避几点问题

1.继承结构尽量不要过于复杂

2.推荐使用mixins机制:在多继承的背景下满足继承的什么"是"什么的关系

posted @ 2020-04-09 22:03  轻描丨淡写  阅读(436)  评论(0编辑  收藏  举报