__mro__是类的只读元组,按C3线性化算法确定的方法解析顺序,包含类自身、所有祖先类及object,决定super()查找路径和属性/方法调用顺序,反映Python实际继承链而非声明顺序。

直接看 __mro__ 就行,它是 Python 对象所属类的继承顺序元组,比手写 isinstance 或递归查 __bases__ 更准、更省事。
什么是 __mro__?它和继承链有什么关系
__mro__(Method Resolution Order)是每个类自动拥有的属性,值为一个 tuple,按从左到右顺序列出该类在方法查找时实际使用的继承路径。它不等于你写的 class A(B, C) 中的括号顺序,而是经过 C3 线性化算法计算后的结果——也就是说,它反映的是 Python 真正“怎么找父类方法”的逻辑。
注意:__mro__ 属于 类,不是实例;但你可以通过实例的 __class__ 拿到它:
class Animal: pass class Mammal(Animal): pass class Dog(Mammal): pass <p>d = Dog() print(Dog.<strong>mro</strong>)</p><h1><class '<strong>main</strong>.Dog'>, <class '<strong>main</strong>.Mammal'>, <class '<strong>main</strong>.Animal'>, <class 'object'></h1><p>print(d.<strong>class</strong>.<strong>mro</strong>) # 和上面一样</p><p><span>立即学习</span>“<a href="https://pan.quark.cn/s/00968c3c2c15" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">Python免费学习笔记(深入)</a>”;</p>
为什么不用 __bases__ 而用 __mro__
__bases__ 只返回直接父类(一层),无法体现多继承下的完整查找顺序,尤其遇到菱形继承时极易误判。而 __mro__ 是最终生效的线性顺序,能准确回答“调用 obj.method() 时,Python 会先去哪个类找?”
-
__bases__是静态声明,__mro__是动态计算(支持super()正常工作) - 如果类用了
__slots__或 metaclass,__bases__不变,但__mro__可能因解析规则变化而不同 - 检查某个类是否在继承链中,用
TargetClass in SomeClass.__mro__比层层遍历__bases__更可靠
常见错误:把 __mro__ 当成实例属性或误读内容
很多人试了 obj.__mro__ 报 AttributeError,是因为它只存在于类对象上;还有人看到输出里有 object 就以为“所有类都显式继承了 object”,其实这是 Python 3 的隐式行为,不必写 class A(object)。
- ❌ 错误写法:
d.__mro__(d是实例) - ✅ 正确写法:
d.__class__.__mro__或Dog.__mro__ - ⚠️ 注意:
__mro__是只读 tuple,不能修改;试图赋值会报AttributeError - ⚠️ 如果类定义时用了
metaclass=ABCMeta,__mro__末尾仍含object,但中间可能插入抽象基类,别漏看
什么时候必须依赖 __mro__ 而不是靠经验猜
当你处理多重继承 + 方法重写 + super() 组合时,仅靠代码缩进或继承声明顺序根本没法预测执行路径。比如:
class A:
def f(self): print("A")
<p>class B(A):
def f(self): print("B"); super().f()</p><p>class C(A):
def f(self): print("C"); super().f()</p><p>class D(B, C):
def f(self): print("D"); super().f()</p><p>D().f() # 输出 D → B → C → A,这个顺序就藏在 D.<strong>mro</strong> 里</p>这个输出顺序不是 B 优先于 C(虽然声明是 class D(B, C)),而是由 D.__mro__ 决定的:(D, B, C, A, object)。没它,你就只能跑一遍才知道。
真正容易被忽略的是:一旦涉及第三方库的 mixin 类、框架的基类(如 Django 的 View、SQLModel 的 SQLModel),它们的 __mro__ 往往嵌套很深,且中间穿插了你不熟悉的类。这时候不打印出来看一眼,光靠文档描述几乎没法 debug 方法覆盖问题。


















