MRO是Python基于C3线性化算法为每个类生成的方法解析顺序,决定同名方法调用时的优先级;它确保局部优先、单调性及父类相对顺序,可通过__mro__或mro()查看,查找时从左到右取第一个匹配实现。

Python多继承中的方法解析顺序(MRO)决定了当多个父类定义了同名方法时,子类调用该方法时实际执行的是哪一个。理解MRO不是为了记住规则,而是避免意外覆盖、定位调用链、写出可维护的继承结构。
什么是MRO?它怎么生成?
MRO是Python为每个类自动计算出的一个线性化类序列,表示方法查找时的优先级顺序。它不是简单按继承括号里的书写顺序排列,而是基于C3线性化算法——兼顾局部优先、单调性和保持父类间相对顺序三个原则。
你可以通过ClassName.__mro__或ClassName.mro()查看结果,返回一个元组或列表,第一个是类本身,最后一个是object。
- 例如:class D(B, C): pass,即使C在B之后定义,只要B和C没有共同祖先,MRO就是(D, B, C, object)
- 但如果B继承自A,C也继承自A,MRO会把A排在B和C之后、object之前,确保A只出现一次且不破坏B→A、C→A的顺序
冲突发生时,MRO如何决定“谁的方法被调用”?
当子类未定义某方法,而多个父类都提供了同名方法时,Python沿MRO从左到右查找,**第一个匹配到的实现即被采用**,后续类中的同名方法被跳过。
立即学习“Python免费学习笔记(深入)”;
- 这意味着:靠前的父类方法具有“屏蔽效应”,即使后面的父类方法逻辑更合理,也不会被触发
- 常见陷阱:写class Child(ParentA, ParentB):时,以为ParentB的方法会生效,结果发现ParentA里恰好有个同名空方法或占位符,导致逻辑静默失效
- 调试建议:遇到行为异常,第一反应不是改逻辑,而是打印Child.__mro__,确认目标方法是否真的在期望位置
如何主动干预或规避MRO带来的问题?
不推荐强行绕过MRO,但可以有意识地设计结构来降低风险:
- 优先用组合代替多继承:把共用行为封装成独立类或工具函数,通过属性调用,而非让子类同时继承多个功能类
- 显式调用父类方法:用super().method()替代硬编码类名,它严格遵循MRO,比ParentA.method(self)更安全、更可演进
- 避免在抽象基类或Mixin中定义可能冲突的通用方法名:比如不要在多个Mixin里都定义setup()、run()等泛用名称;可用前缀区分,如db_setup()、log_run()
- 必要时重写并明确委托:如果确实需要混合两个父类的关键行为,可在子类中重写该方法,用super()分别调用两者,控制执行顺序和条件
一个典型调试场景:为什么super()没按我预期走?
很多人误以为super()只调上一级父类,其实它返回的是MRO中**当前类之后的下一个类**的方法绑定对象。所以super()的行为完全依赖于调用它的类在MRO中的位置。
- 在class C(A, B):中,C的MRO是(C, A, B, object),那么super().__init__()在C.__init__里就等价于A.__init__()
- 但如果A.__init__里也有super().__init__(),它就会继续调用B.__init__(),而不是跳过——这就是协作式多重初始化能正常工作的基础
- 关键点:所有参与协作的类,其__init__(或其他方法)都必须使用super(),否则链条会在某处中断










