跟许多高级语言一样,python支持多继承,使用方式也类似
class ClassName(BaseClass1, BaseClass2, BaseClass3):
'''
多继承举例
'''
在python中需要特别注意,多继承在古典类和新式类中MRO(Method Resolution Order, 方法解析顺序)是不同的。
在python古典类中,MRO采用对继承树自左至右的深度优先遍历(DFS)。一个经典列子:
'''
A
+fun1()
+fun2()
/ \
/ \
/ \
B C
+fun1() +fun1()
+fun2()
\ /
\ /
\ /
D
'''
class A:
def fun1(self):
print "class A, method fun1"
def fun2(self):
print "class A, method fun2"
class B(A):
def fun1(self):
print "class B, method fun1"
class C(A):
def fun1(self):
print "class C, method fun1"
def fun2(self):
print "class C, method fun2"
class D(B, C):
pass
d = D()
d.fun1() #class B, method fun1
d.fun2() #class A, method fun2
用古典类实现,执行D中的fun1, fun2,分别调用B的fun1和A的fun2。根据自左至右深度遍历,继承顺序为D->B->A->C。所以,fun1在B中找到,fun2在A中找到。
DFS算法简单,但是存在一些弊端,在上面的例子中,存在菱形继承关系,C中重写了A的一些方法,将导致D的子类永远无法调用C中重写的方法。
新式类的多继承采用C3 MRO搜索。
'''
object
|
A
+fun1()
+fun2()
/ \
/ \
/ \
B C
+fun1() +fun1()
+fun2()
\ /
\ /
\ /
D
'''
class A:
def fun1(self):
print "class A, method fun1"
def fun2(self):
print "class A, method fun2"
class B(A):
def fun1(self):
print "class B, method fun1"
class C(A):
def fun1(self):
print "class C, method fun1"
def fun2(self):
print "class C, method fun2"
class D(B, C):
pass
d = D()
d.fun1() #class B, method fun1
d.fun2() #class C, method fun2
通过执行结果可以看到新式类与古典类多继承不同。C3 MRO算法的具体描述为:
假定,C1C2,…CN表示类C1到CN的序列,其中序列头部元素(head)= C1,序列尾部(tail)=C2…CN;
C继承的基类自左至右分别为B1, B2, …BN;
mro(C)表示C的线性继承关系,其中mro(object) = object。
算法具体过程:
mro(C(B1, B2, ...BN)) = C + merge( mro(B1), mro(B2)... mro(BN), B1B2...BN)
其中核心算法merge规则:在mro(B1)…mro(BN),B1,…BN中,取mro(B1)的head,如果该元素不在mro(B2), …mro(BN), B1B2…BN的尾部序列中,则添加该元素搞C的线性继承序列中,同时将钙元素从所有的列表中删除(该头元素也叫good head),否则取mro(B2)的head,继续相同的判断,知道整个列表为空或者没有办法找到任何符合要求的头元素(此时引发异常)。
根据算法描述,我们看一下上面的例子。
# O = Object
mro(O) = O
mro(A) = AO
mro(B) = B + merge(mro(A), A) = B + merge(AO, A) = B + A + merge(O) = BAO
mro(C) = C + merge(mro(A), A) = CAO #与mro类似
mro(D) = D + merge(mro(B), mro(C), BC)
= D + merge(BAO, CAO, BC) # BAO的head B,不在CAO、 BC的tail中,将B加入线性序列
= D + B + merge(AO, CAO, C) # AO head A,在CAO的tail中,跳过,取CAO head C
= D + B + C + merge(AO, AO)
= D + B + C + A + O = DBCAO
继承顺序为D->B->C->A->O,所以,fun1在B中找到,fun2在C中找到。
新式类中可以通过 __mro__ 属性查看,D.__mro__的输出:
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <type 'object'>)
多继承在新式类和古典类的搜索顺序不同,要引起注意。同样需要注意,在C3 MRO中,如果找不到good head会引发异常,因此在多继承设计时,应通过尽量减少菱形继承避免这个问题。
http://www.jianshu.com/p/2ZxRsn
http://www.webtag123.com/python/43896.html
http://python.jobbole.com/85685/
91个建议