python 3 是如何处理多继承的?

python 多重继承

当前代码还没错误·

class X(object): pass
class Y(object): pass
class A(X, Y): pass
class B(Y, X): pass

如果加上以下的类 C继承 会出现错误

TypeError                                 Traceback (most recent call last)
<ipython-input-144-1bfe1fb4b3ba> in <module>()
      3 class A(X, Y): pass
      4 class B(Y, X): pass
----> 5 class C(A, B): pass
      6

TypeError: Cannot create a consistent method resolution
order (MRO) for bases X, Y

因为C 类具有二义性的继承关系

多重继承具体分析算法

1,C 类的线性化 结果记作 L[C] = [C1,C2,…CN] , 其中 C1 称为 L[C] 的头,其余元素 [C2,…,CN] 称为尾 这里的尾部定义和常识不同,后面会用到,!!

2,如果一个类 C 继承自基类 B1、B2、……、BN

L[object] = [object]
L[C(B1…BN)] = [C] + merge(L[B1]…L[BN], [B1]…[BN])

merge 输入一组列表,输出是一个列表:

  • 检查第一个列表的头元素(如 L[B1] 的头),记作 H。
  • 若 H未出现在其它列表的尾部,则将其输出,并将其从所有列表中删除,然后回到步骤1;否则,取出下一个列表的头部记作 H,继续该步骤。
  • 重复上述步骤,直至列表为空或者不能再找出可以输出的元素。如果是前一种情况,则算法结束;如果是后一种情况,说明无法构建继承关系,Python 会抛出异常。

例如 上面图中的 A

L[object] = [object]
L[X] = [X, object]
L[Y] = [Y, object]

L[A] = [A] + merge(L[X], L[Y], [X], [Y])
     = [A] + merge([X, object], [Y, object], [X,Y])  # X 未出现在其他的列表尾部
     = [A, X] + merge([object], [Y, object], [Y])。# object 出现在第二个列表尾部
     = [A, X, Y] + merge([object], [object])   # Y 未出现在尾部
     = [A, X, Y, object]  # 列表为空
L[B] = [B, Y, X, object]

计算 L[C] 的 线性化结果

L[C] = [C] + merge(L[A], L[B], [A], [B])
     = [C] + merge([A, X, Y, object], [B, Y, X, object], [A,B])
     = [C, A] + merge([X, Y, object], [B, Y, X, object], [B])
     = [C, A, B] + merge([X, Y, object], [Y, X, object])  # X 虽然是第一个列表的头,但是它出现在了第二个列表的尾部;Y 虽然是第二个列表的头,但是它出现在了第一个列表的尾部 没办法继续计算

此时你可能会有这样的疑问“为什么X 是第二个列表的尾部?Y 为什么是第一个列表的尾部 ?”

如果有此疑问请看上面对于尾部的定义

L[C] 最后没办法输出,但是剩余列表不为空, 所以对于C类无法构建一个没有二义性的继承关系

 python 多重继承的方法解析顺序

class A:
    def say(self):
        print("A Hello:", self)
 
class B(A):
    def eat(self):
        print("B Eating:", self)
 
class C(A):
    def eat(self):
        print("C Eating:", self)
 
class D(B, C):
    def say(self):
        super().say()
        print("D Hello:", self)
    def dinner(self):
        self.say()
        super().say()
        self.eat()
        super().eat()
        C.eat(self)

Python 能区分 d.eat() 调用的是哪个方法, 是因为 Python 会按照特定的顺序遍历继承图,python3就是广度优先。 这个顺序叫方法解析顺序( Method Resolution Order, MRO)。 类都有一个名为 __mro__ 的属性, 它的值是一个元组, 按照方法解析顺序列出各个超类, 从当前类一直向上, 直到object 类。

D 类的 __mro__ 属性如下 :

>>> D.__mro__
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

图例

在python3中调用D继承的save方法  搜索按广度优先 路径D->B->C->A, 执行C中save

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值