zoukankan      html  css  js  c++  java
  • 多继承带来的菱形问题

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

    1586423053645

    这种继承结构下导致的问题称之为菱形问题:如果A中有一个方法,B和/或C都重写了该方法,而D没有重写它,那么D继承的是哪个版本的方法:B的还是C的?如下所示

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


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


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


    class D(B,C):
        pass


    obj = D()
    obj.test() # 结果为:from B

    一、继承原理(MRO)

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

    >>> D.mro() # 新式类内置了mro方法可以查看线性列表的内容,经典类没有该内置该方法
    [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

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

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

    所以obj.test()的查找顺序是,先从对象obj本身的属性里找方法test,没有找到,则参照属性查找的发起者(即obj)所处类D的MRO列表来依次检索,首先在类D中未找到,然后再B中找到方法test

    1.由对象发起的属性查找,会从对象自身的属性里检索,没有则会按照对象的类.mro()规定的顺序依次找下去,
    2.由类发起的属性查找,会按照当前类.mro()规定的顺序依次找下去,

    二、深度和广度的优先级

    非菱形结构:

    参照下述代码,多继承结构为非菱形结构,此时,会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性

    1586423281436

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


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


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


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


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


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


    print(A.mro())
    '''
    [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class 'object'>]
    '''

    obj = A()
    obj.test() # 结果为:from B
    # 可依次注释上述类中的方法test来进行验证

    菱形结构:

    经典类————》python2

    如果继承关系为菱形结构,那么经典类与新式类会有不同MRO,分别对应属性的两种查找方式:深度优先和广度优先1586423326835

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

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

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

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

    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

    obj = A()
    obj.test() # 如上图,查找顺序为:obj->A->B->E->G->C->F->D->object
    # 可依次注释上述类中的方法test来进行验证,注意请在python2.x中进行测试

    新式类————》python3

    1586423387815

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

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

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

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

    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

    obj = A()
    obj.test() # 如上图,查找顺序为:obj->A->B->E->C->F->D->G->object
    # 可依次注释上述类中的方法test来进行验证
    总结:
    多继承到底要不用???
    要用,但是规避几点问题
    1、继承结构尽量不要过于复杂
    2、推荐使用mixins机制:在多继承的背景下满足继承的什么"是"什么的关系
  • 相关阅读:
    算法设计之hash---hash 函数、hash表
    图像处理之换脸---手把手教你使用 Deepfakes 换脸
    图像处理之搜图---实现以图搜图
    机器学习之python---Python实现逻辑回归(LogisticRegression)
    嵌入式开发之usb 转 net --- 支持持USB 网络适配器方案
    嵌入式开发之网卡--- Ethernet 以太网 MAC、MII、PHY、MDIO、IEEE802.3 详解
    机器学习之RNN ---LSTM原理及实现详解
    Docker的学习
    网络7层 4层 5层 协议
    netstat 查看端口、进程占用
  • 原文地址:https://www.cnblogs.com/bailongcaptain/p/12670533.html
Copyright © 2011-2022 走看看