最直接有效的方式是查__mro__,它明确告诉你python实际按什么顺序找属性:myclass.__mro__返回元组,从左到右即属性查找顺序;实例用obj.__class__.__mro__;super()也严格遵循该顺序。

最直接有效的方式是查 __mro__,它明确告诉你 Python 实际按什么顺序找属性,而不是你“以为”的继承顺序。
看类的 MRO 路径
每个类都有 __mro__ 属性,返回一个元组,从左到右就是属性和方法的真实查找顺序:
- 用
MyClass.__mro__查看类本身的 MRO - 对实例,可用
obj.__class__.__mro__ - 结果里第一个是类自身,最后一定是
object
例如:class Z(K1, K3, K2): pass,运行 Z.__mro__ 就能立刻看到 Python 是先查 K1、再 K3 还是跳过某个父类——不用猜,也不用画图。
验证属性实际来自哪一层
当你访问 obj.attr 得到某个值,但不确定它定义在哪,可以逐层检查:
- 遍历
obj.__class__.__mro__中的每个类 - 用
hasattr(cls, 'attr')或直接查cls.__dict__.get('attr') - 第一个返回非
None的类,就是该属性的实际来源
这样比在代码里反复注释/打印更可靠,尤其适合嵌套深、分支多的继承结构。
留意实例属性与类属性的区别
属性查找顺序是:实例 → 类 → 父类(按 MRO),但这两类属性行为不同:
- 实例属性(如
self.x = 1)只属于当前对象,不参与继承查找 - 类属性(如
x = 1在 class 内)才走 MRO;子类重定义同名类属性会覆盖父类的 - 如果误把本该是实例属性的写成类属性,可能在多个实例间意外共享
调试时建议先确认你要查的是哪一类属性,再决定查 obj.__dict__ 还是 obj.__class__.__mro__。
用 super() 时注意它也走 MRO
super() 不是简单调父类,而是按当前类的 MRO 找“下一个”类:
-
super().__init__()调用的是 MRO 中当前类之后的第一个有该方法的类 - 如果某层没实现
__init__,会继续往后找,直到object - 多继承中
super()的行为完全依赖 MRO,不是固定调左边第一个父类
所以遇到 super() 调用异常或跳过预期类,第一反应应该是检查 __mro__ 是否符合预期。











