Vanson's Eternal Blog

Python中的方法解析顺序MRO详解

Python mro.png
Published on
/4 mins read/---

Python MRO

Python 的 ‌MRO(Method Resolution Order,方法解析顺序)‌ 是解决多重继承中方法调用顺序的核心机制。

其核心逻辑基于 ‌C3 线性化算法‌,通过严格的规则保证继承关系的合理性。

C3 线性化算法

MRO 的生成必须满足以下三个关键条件:

‌单调性

如果类 A 在类 B 之前出现在 MRO 中,则 ‌A 的所有子类也必须出现在 B 之前‌ 例:若 Child → Parent → object 是合法的 MRO,则 GrandChild → Child → Parent → object 也必须成立

局部优先顺序

类声明时父类的 ‌书写顺序决定优先级‌ 例:class D(B, C) 的 MRO 中,B 必须出现在 C 之前

一致性

继承关系图中 ‌不能出现循环依赖‌ 例:A → B → A 的循环继承会抛出 TypeError

MRO 计算的具体步骤

以继承关系 D(B, C) 且 B(A), C(A) 为例,逐步演示 C3 算法:

 
    D
   / \
  B   C
   \ /
    A
 
 

递归计算线性化

‌计算 D 的 MRO‌:L(D) = D + merge(L(B), L(C), [B, C])

‌计算 B 的 MRO‌: L(B) = B + merge(L(A), [A]) = B → A → object

‌计算 C 的 MRO‌: L(C) = C + merge(L(A), [A]) = C → A → object

‌合并操作(merge)‌:

  • 输入列表:[B → A → object], [C → A → object], [B, C]
  • ‌合并规则‌:取第一个列表的头部,如果该头部不在其他列表的尾部,则提取它
  • 第一次提取:B(不在其他列表尾部) → 结果 D → B
  • 剩余列表:[A → object], [C → A → object], [C]
  • 第二次提取:C(不在其他列表尾部) → 结果 D → B → C
  • 剩余列表:[A → object], [A → object]
  • 最终合并:D → B → C → A → object

关键场景解析

菱形继承

 
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass
 
print(D.__mro__)  
# 输出:(D, B, C, A, object)
 
 

复杂多重继承

"""
错误原因‌:B 的 MRO 是 B → Y → X → object,A 的 MRO 是 A → X → Y → object
‌冲突点‌:X 和 Y 的顺序在父类中不一致,无法合并,触发 TypeError
"""
class X: pass
class Y: pass
class A(X, Y): pass
class B(Y, X): pass
class C(A, B): pass  # 这里会报错!
 
 

super() 的工作机制

super() 的本质是 ‌按 MRO 顺序调用下一个类的方法‌,而非直接调用父类方法。

"""
D.__mro__ = (D, B, C, A, object)
调用链:D.show() → B.show() → C.show() → A.show()
"""
class A:
    def show(self):
        print("A")
 
class B(A):
    def show(self):
        print("B-start")
        super().show()  # 调用 MRO 中的下一个类(A)
        print("B-end")
 
class C(A):
    def show(self):
        print("C-start")
        super().show()  # 调用 MRO 中的下一个类(A)
        print("C-end")
 
class D(B, C):
    def show(self):
        print("D-start")
        super().show()  # 调用 MRO 中的下一个类(B)
        print("D-end")
 
d = D()
d.show()
 
 
 
D-start
B-start
C-start
A
C-end
B-end
D-end
 
 

开发实践

调试

print(ClassName.__mro__)   # 查看 MRO 顺序
print(inspect.getmro(cls)) # 获取 MRO 元组
 
 

设计原则‌

  • 避免超过 3 层的多重继承
  • 使用 ‌Mixin 类‌ 代替直接多重继承
  • 优先选择组合模式(Composition over Inheritance)

循环依赖错误

# 错误:循环继承
class A(B): pass
class B(A): pass  # 触发 TypeError