6. 方法解析顺序MRO
钻石继承(菱形继承)问题
示例
class A:
pass
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
上述程序的继承关系图:
object
|
A
/ \
B C
\ /
D
上述程序构成了钻石继承的基本要素。下面我们为ABCD四个类添加方法 m 如下:
# 方法解析顺序MRO 示例
# https://weimingze.com
class A:
'A类'
def m(self):
print('A')
class B(A):
'B类'
def m(self):
print('B')
class C(A):
'C类'
def m(self):
print('C')
class D(B, C):
'D类'
def m(self):
print('D')
d = D()
d.m() # 调用哪个方法?
上述程序打印结果为:D
多继承说明
- 一个子类同时继承自多个父类,父类中的方法可以同时被继承下来。
- 如果两个父类中有同名的方法,而在子类中又没有覆盖此方法时,调用结果难以确定。
去掉类D的方法m,如下
# 方法解析顺序MRO 示例
# https://weimingze.com
class A:
'A类'
def m(self):
print('A')
class B(A):
'B类'
def m(self):
print('B')
class C(A):
'C类'
def m(self):
print('C')
class D(B, C):
'D类'
d = D()
d.m() # 调用哪个方法?
上述程序打印结果为:B,此时B的基类是A,那去掉 B 的 m方法试试。
去掉类B的方法m,如下.
# 方法解析顺序MRO 示例
# https://weimingze.com
class A:
'A类'
def m(self):
print('A')
class B(A):
'B类'
class C(A):
'C类'
def m(self):
print('C')
class D(B, C):
'D类'
d = D()
d.m() # 调用哪个方法?
上述程序打印结果为:C,并不是调用B的基类A的 m方法。
上述程序调用m方法遵循的是方法解析顺序MRO。
什么是方法解析顺序
方法解析顺序(Method Resolution Order, MRO)是在多继承场景下确定方法调用顺序的规则。
作用:
当类继承自多个父类,且这些父类中有同名方法时,MRO决定了Python解释器查找方法的顺序。
__mro__属性
mro属性绑定一个元组,此元组记录的是此子类的所有基类。基类的先后顺序表示方法的查找次序。
super() 函数就是依据此属性对父类的方法进行查找的。
示例:
# 方法解析顺序MRO 示例
# https://weimingze.com
class A:
'A类'
def m(self):
print('A')
class B(A):
'B类'
def m(self):
print('B')
class C(A):
'C类'
def m(self):
print('C')
class D(B, C):
'D类'
def m(self):
print('D')
d = D()
d.m() # 调用哪个方法?
print(D.__mro__)
打印结果是
D
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
这个元组就是MRO列表,他的先后顺序也是D类的方法查找顺序。
super() 函数在调用父类方法时,它也是依赖MRO列表来进行查找的。