子类重写__init__但未调用super().__init__()会导致父类实例属性未创建,访问时抛AttributeError;需显式调用父类__init__以履行继承契约。

子类重写 __init__ 但没调用 super().__init__() 会怎样?
直接后果是父类定义的实例属性(比如 self.name、self.config)根本不会被创建,后续访问时抛出 AttributeError。这不是语法错误,运行到第一次用到该属性才崩,容易漏测。
常见于继承 Exception、threading.Thread、自定义基类等场景。比如:
class MyError(Exception):
def __init__(self, message):
self.message = message # ❌ 忘了调用 super().__init__(message)
self.code = 500
<p>raise MyError("timeout") # 后续 .args 或 .str() 可能异常,因为 Exception.<strong>init</strong> 没执行
怎么确认是不是这个原因?
别猜,直接查属性来源。在子类 __init__ 结尾加一行:
print([attr for attr in dir(self) if not attr.startswith('_')])对比父类文档中声明的公有属性(如 Exception.args、socket.timeout.errno),看是否缺失。也可以用 hasattr(self, 'expected_attr') 在关键位置断言。
立即学习“Python免费学习笔记(深入)”;
更准的方法是检查父类 __init__ 做了什么——它往往初始化了核心字段或做了状态校验,跳过就等于绕过契约。
修复方式:必须显式调用父类 __init__
不是“建议”,是契约义务。Python 不会自动帮你调,哪怕父类 __init__ 是空的,也可能未来加逻辑。
- 用
super().__init__(...)(推荐):兼容多重继承,参数传递清晰 - 用
ParentClass.__init__(self, ...)(慎用):硬编码父类名,重构时易出错;若父类改名或换层级,这里就静默失效 - 参数必须匹配父类签名:比如
Exception.__init__接收*args,你传message单个值没问题,但若父类要求code和message都传,少一个就会报TypeError
修复示例:
class MyError(Exception):
def __init__(self, message, code=500):
super().__init__(message) # ✅ 补上这一行
self.code = code
容易被忽略的复杂点
多重继承下,super() 调用顺序由 MRO 决定,不是简单“上一级”。如果父类链里多个类都重写了 __init__,只在最底层补一句 super().__init__() 不够,每层都得接力调用,否则中间某层的初始化就被跳过了。
还有种隐蔽情况:父类 __init__ 本身依赖其他方法(比如 self._setup()),而子类重写了该方法但逻辑不完整——这时即使调了 super().__init__(),仍可能因依赖方法行为异常导致属性未正确设置。


















