Python多继承未调用父类构造是否合规?如何用super处理带参构造?
多继承中未调用父类构造函数的疑问及super()的使用困惑
问题背景
我成功通过多继承构造了一个Python对象,但感觉所用方式并不规范。
我的代码
class A: def __init__(self, a): print("A ctor called!") self.a_ = a def printa(self): print(self.a_) class B: def __init__(self, b): print("B ctor called!") self.b_ = b def printb(self): print(self.b_) class C(A, B): def __init__(self, a, b, c): self.a_ = a self.b_ = b self.c_ = c
执行代码及输出
执行:
c = C(11, 22, 33) c.printb()
输出:
22
疑问点
- 构造C类对象时并未调用A类和B类的构造函数,但结果符合预期,这种情况是否正常?是不是操作有误?
- 知道应该使用
super()函数,但不知道如何在多继承场景下用它调用两个带参数的父类构造函数。 - 我的问题被标记为重复,但我认为并非完全重复:相关话题未涉及带参数的构造函数问题,而我的问题核心正是参数带来的困扰。
1. 未调用父类构造函数却能运行的原因
这种情况是正常的,但属于不规范的写法。
Python中,子类如果重写了__init__方法,默认不会自动调用父类的__init__。你的代码里,C类自己手动设置了self.a_和self.b_,刚好和A、B类构造函数要初始化的属性同名,所以调用printa()、printb()时能正常访问到属性。
但这种写法有严重隐患:
- 如果父类构造函数里还有其他逻辑(比如打印日志、初始化其他隐藏属性、连接资源等),这些逻辑完全不会执行,可能导致父类功能异常。
- 如果后续父类修改了属性名或构造逻辑,子类代码会直接失效,维护性极差。
2. 多继承下用super()调用带参数的父类构造函数
要正确处理多继承的构造函数调用,关键是让所有父类的__init__都遵循协作式调用的规范——每个父类的__init__都要调用super().__init__(),并接受额外的关键字参数(避免参数冲突)。
调整后的代码示例:
class A: def __init__(self, a, **kwargs): print("A ctor called!") self.a_ = a super().__init__(**kwargs) # 传递剩余参数给下一个父类 class B: def __init__(self, b, **kwargs): print("B ctor called!") self.b_ = b super().__init__(**kwargs) # 即使B没有后续父类,这行也无害(会调用object的__init__) class C(A, B): def __init__(self, a, b, c): super().__init__(a=a, b=b) # 通过关键字参数传递父类需要的参数 self.c_ = c
执行c = C(11,22,33)时,输出会是:
A ctor called! B ctor called!
此时调用c.printa()和printb()也能正常输出,同时父类的构造逻辑都被执行了。
为什么要这么写?
- Python的多继承是基于**方法解析顺序(MRO)**的,
super()会自动按照MRO顺序调用下一个类的方法。C的MRO是[C, A, B, object],所以super().__init__()在A中会调用B的__init__,在B中会调用object的__init__。 - 使用关键字参数传递,可以避免不同父类的参数顺序冲突,让代码更健壮。
- 这种写法符合Python的设计规范,即使后续添加或调整父类,代码也能保持兼容。
3. 关于"重复问题"的补充
你提到的话题虽然基础,但带参数的多继承构造确实是容易混淆的点。核心差异就在于必须让父类通过**kwargs接受并传递剩余参数,否则会出现参数不匹配的错误。只要掌握了协作式调用的规范,带参数的多继承构造就能正确实现。
内容的提问来源于stack exchange,提问作者Autechre
相关产品推荐
相关产品推荐

