在子类__init__中必须用super().__init__()调用父类初始化,关键是按父类参数要求准确传参,避免硬编码父类名,多重继承时需各父类协作传递**kwargs,通过MRO和日志调试确保参数流转正确。
在子类 __init__ 中调用 super().__init__(),核心是让父类完成它该负责的初始化,同时不破坏继承链的协作性。关键不在“能不能调”,而在于“怎么传参”和“谁来收参”。
必须传参:父类需要什么,子类就得给什么
父类的 __init__ 如果定义了形参(比如 name、age),子类不能只写 super().__init__() 就完事——那会触发默认值或报错。
- 如果父类是
def __init__(self, name, age):,子类就得把这两个值明确传进去:super().__init__(name, age) - 如果父类用关键字参数(推荐用于多重继承):
def __init__(self, *, name, **kwargs):,子类就应传super().__init__(name=name, **kwargs) - 漏传、错传或类型不匹配,都会导致父类属性未设置、值为
None,或直接抛TypeError
避免硬编码父类名:用无参 super() 更安全
写 Parent.__init__(self, ...) 或 super(Parent, self).__init__(...) 是危险的:
- 前者绕过 MRO,可能跳过中间类;后者在动态继承或重构时极易出错(例如报
TypeError: super() argument 1 must be type, not str) - Python 3 推荐统一用
super().__init__(...),它自动按当前类的 MRO 查找下一个类,语义清晰且可扩展 - 哪怕单继承,也建议用无参
super(),为将来可能的多继承留余地
多重继承时:所有类都要协作,不能有“掉队者”
当子类继承多个父类(如 class Flat(Place, Product):),初始化不是“分别调一次”,而是一条委托链:
- 每个父类
__init__都必须以super().__init__(**kwargs)结尾,把剩余参数往下传 - 每个类只解包自己关心的关键字参数(用
*分隔,如def __init__(self, *, country, city, **kwargs):),不碰其他参数 - 最终由
object.__init__()接收空**kwargs并静默结束,整条链才完整可靠
调试小技巧:看 MRO 和参数流向
不确定初始化是否走对了?两步验证:
- 查 MRO:
print(YourClass.__mro__),确认父类顺序是否符合预期(如(Flat, Place, Product, object)) - 加日志:在每个
__init__开头打印接收的参数,观察谁取了什么、谁传了什么,快速定位漏参或错参环节 - 别依赖 IDE 自动补全——它不一定反映真实 MRO,运行时才是唯一标准










