菱形继承是结构确定时必然出现的问题,只要D同时继承B和C且B、C均继承A,就形成菱形结构;Python通过C3线性化算法生成MRO列表决定方法查找顺序,D.mro()可直接验证,同名方法按MRO从左到右匹配首个有效实现。

菱形继承不是“容易引发”,而是结构确定时必然出现
只要类 D 同时继承 B 和 C,而 B、C 又都继承自同一个 A,菱形结构就已形成——这不是概率问题,是继承关系图的客观结果。Python 不会阻止你写出这种结构,它只负责在调用 method() 或初始化 __init__() 时按 MRO 规则选一个路径执行。
D.mro() 决定一切,但很多人没真看过它
Python 用 C3 线性化算法生成 MRO 列表,决定方法和属性查找顺序。不查 D.mro(),光靠脑补“B 在前所以优先”很容易错。
- 执行
print(D.mro())是最直接的验证手段,输出类似[<class>, <class>, <class>, <class>, <class>]</class></class></class></class></class> - MRO 严格从左到右匹配,第一个含目标属性的类胜出;
A即使是共同祖先,也只被访问一次 - 如果 B 和 C 都重写了
method(),那么D().method()调用的永远是B.method()(前提是 B 在 MRO 中排 C 前)
用 super() 初始化时,参数传递不匹配就会静默失败
菱形结构下,A.__init__() 理论上该只执行一次,但若 B、C 各自用类名方式调用 A.__init__(self, ...),A 就会被初始化两次——而用 super() 要求所有父类构造函数签名兼容,否则 **kwargs 传不下去,或某层直接抛 TypeError: __init__() got an unexpected keyword argument。
- 所有参与菱形链的类(A、B、C、D)的
__init__()必须接受**kwargs并原样传给super() - 不能有某个类硬写死只收两个位置参数,而另一个期待三个命名参数
- 推荐统一用
def __init__(self, *, name=None, age=None, **kwargs):风格,显式声明关键字参数
同名方法冲突不是报错,而是静默覆盖——这最危险
Python 不禁止 B 和 C 都定义 save(),也不会警告你 D 调用时到底走哪边。它只是按 MRO 拿第一个匹配的。问题在于:这个“第一个”取决于你在定义 class D(B, C): 时写的顺序,而不是逻辑优先级。
立即学习“Python免费学习笔记(深入)”;
-
class D(B, C):→ MRO 中 B 在 C 前 →B.save()生效 -
class D(C, B):→ MRO 中 C 在 B 前 →C.save()生效 - 如果 B 和 C 的
save()行为不可互换(比如一个写本地、一个发 HTTP),顺序写反就是线上 bug
真正难缠的从来不是菱形结构本身,而是没人检查 MRO、没人约束构造函数签名、没人意识到同名方法的调用路径其实完全由类定义时的括号顺序决定。


















