python多重继承顺序_带你吃透python的多重继承顺序

python的类分为两种类型: 经典类(python2的默认类)和新式类(python3的默认类),经典类在继承的时候采用深度优先的顺序,而新式类的继承顺序则采用广度优先(从左到右)的顺序。

在python3中继承可以直接写成 super().方法名(参数)

而在python2继承必须写成 super(父类,self).方法名(参数)

这里我们重点讨论新式类的继承顺序,

先看一个简单的例子: 新建四个类(A, B, C, D),其中B和C都继承了A,而D继承了B和C。继承关系图

class A:

def __init__(self):

print('A')

super().__init__()

def process(self):

print('A is processing')

class B(A):

def __init__(self):

print('B')

super().__init__()

class C(A):

def __init__(self):

print('C')

super().__init__()

def process(self):

print('C is processing')

class D(B, C):

def __init__(self):

print('D')

super().__init__()

d = D()

# 输出结果如下:

D

B

C

A

新式类继承顺序:D->B->C->A, 广度优先,从左到右。(注意每个类里print函数是写在_init_前面的)

事实上类中的_mro_属性(method resolution order)中定义了继承顺序,我们可以打印出来验证一下:

print(D.__mro__)

# 输出结果

(,

,

,

,

)

正是我们预期的继承顺序。

我们再来看一下如果执行d.processing,到底执行了哪个类里的函数呢?

d.process()

# 输出结果

C is processing

注意B类里并没有process函数,所以按照D->B->C->A的顺序,会在C里先找到process函数。

我们再来看一个例子,这个例子大部分人都会搞错继承顺序!因为你会发现不能用标准的广度优先的顺序来解释继承顺序!

class X(object):

pass

class Y(object):

pass

class Z(object):

pass

class A(X, Y):

pass

class B(Y, Z):

pass

class M(A, B, Z):

pass

print(M.mro())

# 输出结果:

# [,

# ,

# ,

# ,

# ,

# ,

# ]

继承顺序是M->A->X->B->Y->Z,有人会问,X为什么会在B的前面?如果按照广度有限的逻辑,继承顺序不应该是MABXYZ吗?

这里我们就要用MRO的定义来计算并解释一下了:

python2.3以后的版本里,MRO都是通过

我们把L[C]定义为类C的的linearization值(也就是MRO里的继承顺序,后面简称L值),计算逻辑如下:

L[C] = C + merge of linearization of parents of C and list of parents of C in the order they are inherited from left to right.

即L[C]等于C的所有上一级父类的L值的融合,融合的逻辑我们在下面的计算过程中解释:

我们从上往下依次计算每一个类的L值,

首先我们把object类的L值定义为O,即L(object) = O,

接下来根据我们的融合方法,L(X) = X + merge(L(object)) = X+O = XO(因为merge里面只有O)

同样的,L(Y) = YO, L(Z) = ZO,

下面一层 L(A) = A + merge(L(X), L(Y), XY), 我们把刚才已经计算好的L(X), L(Y)带入以后得到:

L(A) = A + merge(XO, YO, XY), 这里我们重点讲一下融合的逻辑,merge函数里,即从左到右,选出第一个没有被merge函数里其他类继承的类,提取到merge函数外,这里我们首先找到X既没有被O继承,也没有被Y继承,所以首先提取到外面,即merge(XO, YO, XY) = X + merge(O, YO, Y),

然后相同的逻辑我们接着把Y提取出来,注意merge函数里有一个YO,说明Y继承了O,所以O并不是第一个不被继承的类,

整个逻辑总结下来就是:

L(A) = A + merge(L(X), L(Y), XY)

= A + merge(XO, YO, XY)

= A + X + merge(O, YO, Y)

= A + X + Y + merge(O, O)

= A + X + Y + O

= AXYO

这里注意一下L(A)的merge函数里不仅有L(X), L(Y)还有一个XY(即A的上一层的所有类从左到右排列的集合)

同样的逻辑我们来计算一下L(B):

L(B) = B + merge(L(Y), L(Z), YZ)

= B + merge(YO, ZO, YZ)

= B + Y + merge(O, ZO, Z)

= B + Y + Z + merge(O, O)

= B + Y + Z + O

= BYZO

最后就是最重要的L(M)了:

L(M) = M + merge(L(A), L(B), AB)

= M + merge(AXYO, BYZO, AB)

= M + A + merge(XYO, BYZO, B) # X是一个没有被其他类继承的类

= M + A + X + merge(YO, BYZO, B)

= M + A + X + B + merge(YO, YZO)

= M + A + X + B + Y + merge(O, ZO)

= M + A + X + B + Y + Z + O

= MAXBYZO

这就解释了为什么X的顺序在B之前,即使B的级别更低,这也说明了我们不能用标准的广度优先的顺序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值