方法解析顺序 (Method Resolution Order, 简称 MRO) 定义了 Python 在类及其父类中搜索方法的顺序。当一个方法存在于继承链中的多个类里时,尤其是涉及多重继承时,了解这一点就变得至关重要。
让我们看一个例子,看看当父类和子类同时拥有同名方法时,Python 是如何决定执行哪一个的。
class A:
def fun(self):
print("In class A")
class B(A):
def fun(self):
print("In class B")
a = B()
a.fun()
输出结果
In class B
原理解析:
- 当调用
obj.fun()时,Python 首先在类 B 中查找。 - 由于 B 定义了
fun(),它就会直接运行该方法,而不再去检查类 A。 - 这里的 MRO 顺序是:B -> A。
多重继承(菱形继承问题)
在多重继承中,一个子类可以继承自多个父类。当这些父类又继承自同一个基类时,这种结构就形成了一个“菱形”,Python 必须决定应该使用哪个类的方法。
class A:
def fun(self):
print("In class A")
class B(A):
def fun(self):
print("In class B")
class C(A):
def fun(self):
print("In class C")
class D(B, C):
pass
a = D()
a.fun()
输出结果
In class B
原理解析:
- D 继承自 B 和 C。
- Python 遵循的 MRO 顺序是:D -> B -> C -> A。
- 由于 B 中存在
fun(),它被执行,搜索也就停止了。
MRO 中的 C3 线性化算法
Python 使用 C3 线性化算法来决定调用方法时搜索类的顺序。该算法会生成一个单一的、一致的顺序,既尊重继承关系,也尊重父类在代码中的书写顺序。
示例: 这个程序打印了 Python 在方法查找时使用的确切顺序。
class A:
def fun(self):
print("In class A")
class B(A):
def fun(self):
print("In class B")
class C(A):
def fun(self):
print("In class C")
class D(B, C):
pass
obj = D()
obj.fun()
print(D.__mro__)
输出结果
In class B
(, , , , )
原理解析:
- 当调用 INLINECODE7487e249 时,Python 遵循 INLINECODE93d84da2 显示的 MRO 顺序。
- 它会依次检查 D,然后 B,然后 C,最后是 A。
- 由于 B 定义了
fun(),该方法被执行,搜索停止。
查看类方法解析顺序 (MRO) 的方法
Python 为我们提供了两种方式来检查一个类的方法解析顺序 (MRO):
- mro 属性: 显示一个元组,包含 Python 搜索方法时所依据的类顺序。
- mro() 方法: 返回一个包含 MRO 顺序的列表。
class A:
def fun(self):
print("In class A")
class B:
def fun(self):
print("In class B")
class C(A, B):
def __init__(self):
print("Constructor C")
obj = C()
print(C.__mro__)
print(C.mro())
输出结果
Constructor C
(, , , )
[, , , ]
原理解析:
C.__mro__以元组的形式返回方法解析顺序。C.mro()以列表的形式返回相同的顺序。- 这个顺序序列表明,当解析任何方法调用时,Python 会先搜索 C,然后是 A,接着是 B,最后是
object。
相关文章:
> – Python 中的多重继承