You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用super().__init__报错但直接调用父类__init__正常的原因探究

问题:super()与直接调用父类__init__的差异分析

代码示例

class A:
    def __init__(self, a, b, c, d=0, e=0, f=0):
        self.a = a
        self.b = b
        self.c = c
        self.d = d
        self.e = e
        self.f = f


class B(A):
    def __init__(self, a, b, c, d, **kwargs):
        super().__init__(a, b, d, **kwargs)
        # A.__init__(self, a, b, d, **kwargs)
        self.c = c


class C(A):
    def __init__(self, a, b, c, d, **kwargs):
        super().__init__(a, b, d, **kwargs)
        # A.__init__(self, a, b, d, **kwargs)
        self.c = c


class D(B, C):
    def __init__(self, a, b, c, d, e, **kwargs):
        super().__init__(a, b, c, e, **kwargs)
        # B.__init__(self, a, b, c, e, **kwargs)
        C.__init__(self, a, b, d, e)


class E(D):
    def __init__(self, a, b, c, d, e=0, **kwargs):
        super().__init__(a, b, c, d, e, **kwargs)
        # D.__init__(self, a, b, c, d, e, **kwargs)


if __name__ == '__main__':
    E(None, None, None, 0)

报错信息

Traceback (most recent call last):
  File "/Users/user/Library/Application Support/JetBrains/PyCharm2023.2/scratches/scratch_5.py", line 39, in <module>
    E(None, None, None, 0)
  File "/Users/user/Library/Application Support/JetBrains/PyCharm2023.2/scratches/scratch_5.py", line 34, in __init__
    super().__init__(a, b, c, d, e, **kwargs)
  File "/Users/user/Library/Application Support/JetBrains/PyCharm2023.2/scratches/scratch_5.py", line 27, in __init__
    super().__init__(a, b, c, e, **kwargs)
  File "/Users/user/Library/Application Support/JetBrains/PyCharm2023.2/scratches/scratch_5.py", line 13, in __init__
    super().__init__(a, b, d, **kwargs)
TypeError: C.__init__() missing 1 required positional argument: 'd'

用户疑问

替换所有super().__init__为直接调用父类__init__(如注释中的写法)后代码可正常运行,想知道:

  1. 两种调用方式结果不同的原因
  2. super().__init__的工作机制
  3. 简化逻辑class A(B,C)中super().__init__()等同于B.__init__()是否错误

解答

核心结论:super()遵循MRO方法解析顺序,而非固定指向定义时的第一个父类

1. Python的MRO(方法解析顺序)

Python在处理多继承时,会为每个类生成一个线性的方法查找顺序(MRO),它决定了调用父类方法时的优先级。你的代码中,类E的MRO为:
E → D → B → C → A → object

2. super()的真实工作逻辑

super()并不是简单指向当前类的直接父类,而是根据调用该方法的实例的MRO,找到当前类在MRO中的下一个类。

在报错场景中:

  • 创建E实例时,调用链为:E.__init__ → D.__init__ → B.__init__
  • 当执行B.__init__里的super().__init__(a, b, d, **kwargs)时,由于当前实例的MRO是E→D→B→C→A→object,super()指向的是MRO中B的下一个类——C,而非B的直接父类A
  • 但C.__init__要求传入a,b,c,d四个必选参数,B只传了a,b,d,缺少c参数,因此触发TypeError

3. 直接调用父类__init__的差异

当你将super().__init__替换为A.__init__(self, ...)时,是直接指定调用A的构造方法,完全绕过了MRO的自动查找逻辑,不会触发C.__init__,因此不会出现参数不匹配的问题。

4. 你的简化逻辑为什么错误

对于代码:

class A(B, C):
    def __init__(self):
        super().__init__()  # 这不等同于B.__init__()吗?

这个逻辑仅在单继承场景下成立。在多继承中:

  • 如果是A自身的实例调用__init__,super()确实指向B
  • 但如果A被其他多继承类(比如D(A, X))继承,当D的实例调用A.__init__时,super()指向的是X而非B

简言之,super()的指向始终由调用它的实例的MRO决定,而非定义它的类的父类顺序。


内容的提问来源于stack exchange,提问作者a82fd72deb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 06:05:00