必须统一用super()且所有类__init__都要接受并透传kwargs,否则在钻石继承中a.__init__会被重复调用两次;显式调用父类__init__绕过mro,破坏协作机制;mro顺序可通过d.__mro__直接验证,所有__init__必须兼容kwargs签名以保障参数链完整。

必须统一用 super(),且所有类(包括最顶层基类)的 __init__ 都要接受并透传 **kwargs。不这么做,重复初始化就是必然结果。
为什么显式调用父类 __init__ 会重复执行
显式写 A.__init__(self) 完全绕过 MRO,变成硬编码跳转。当 B 和 C 都这么干,而 D(B, C) 又分别调 B.__init__ 和 C.__init__,A.__init__ 就被触发两次。
-
D.__mro__是(D, B, C, A, object),但显式调用让 Python “看不见”这个顺序 - 哪怕
B和C都继承自A,它们各自调一次A.__init__就是两次——没有协调机制 - 这种写法在单继承里没问题,一进钻石结构就崩
怎么验证当前类真实的 MRO 顺序
别猜、别查文档、别依赖 IDE 提示——直接运行 print(D.__mro__)。输出是元组,顺序即方法实际查找路径,也是 super() 的行走路线。
- 如果报
TypeError: Cannot create a consistent method resolution order (MRO),说明继承定义时就冲突了,比如A(X, Y)和B(Y, X)同时被C(A, B)继承 -
help(D)开头也会显示 MRO,但不如__mro__直观干净 - 运行时不会变,它在类定义完成那一刻就被 C3 算法锁定
所有 __init__ 必须支持 **kwargs
哪怕某个类当前没参数,也要写成 def __init__(self, **kwargs): 并调 super().__init__(**kwargs)。否则参数链会在某一层断掉。
- 下游类可能通过不同路径传入不同参数(比如
B传a=1,C传b=2),**kwargs是唯一能兼容的签名 - 最顶层基类也得接住并忽略未处理的参数,否则
super().__init__(**kwargs)会因签名不匹配抛TypeError - 不推荐用固定参数 + 默认值替代,容易漏传或覆盖
MRO 不是调试技巧,而是 Python 多继承的运行契约;super() 不是语法糖,是协作协议。漏掉任意一个类的 **kwargs 或某处显式调用,整个链就失效——问题往往不出现在出错的那一行,而在上游某处无声的遗漏。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











