Python中MRO机制疑问:多继承下super调用异常及解决方案
Python继承中super调用问题解析与解决
问题原因
你遇到的核心问题是Python的**方法解析顺序(MRO)**在起作用。当你创建C类的实例时,self是C的对象,它的MRO顺序是:C → A → B → Base → object。
在A的__init__里使用super(A, self)时,super会从MRO中A的下一个类开始查找方法,也就是B,而非你以为的Base。这就导致调用了B的__init__,但B的__init__只接受1个参数,你传了2个,自然报错。
另外你代码里还有个小问题:C的__init__中第二次调用A.__init__(self, attr2)时,A的__init__需要3个参数(self、attr、attr_base1、attr_base2),这里只传了2个,也会引发参数不匹配错误。
解决方案
方案1:直接显式调用Base的__init__
如果你明确要让A的初始化直接调用Base的方法,绕过MRO的链式查找,直接写Base.__init__(self, attr_base1, attr_base2)即可:
class Base(object): def __init__(self, attr_base1, attr_base2): self.attr_base1 = attr_base1 self.attr_base2 = attr_base2 def foo(self): print ('A.foo()') class A(Base): def __init__(self, attr, attr_base1, attr_base2): # 直接调用Base的初始化方法,跳过MRO Base.__init__(self, attr_base1, attr_base2) self.attr1 = attr class B(Base): def __init__(self, attr): self.attr2 = attr def foo(self): print ('B.foo()') class C(A, B): def __init__(self, attr1, attr2): # 修复第二次调用的参数问题 A.__init__(self, attr1, "b1", "b2") # 如果要初始化B的属性,直接调用B的__init__ B.__init__(self, attr2) c = C(1, 2) print(c.attr1, c.attr_base1, c.attr_base2, c.attr2) # 输出 1 b1 b2 2
方案2:调整类的初始化方法适配MRO
如果想保留super的链式调用,需要让所有相关类的__init__都兼容MRO链,比如给B的__init__添加super调用,并处理可变参数:
class Base(object): def __init__(self, attr_base1, attr_base2): self.attr_base1 = attr_base1 self.attr_base2 = attr_base2 def foo(self): print ('A.foo()') class A(Base): def __init__(self, attr, attr_base1, attr_base2, *args, **kwargs): super().__init__(attr_base1, attr_base2) self.attr1 = attr class B(Base): def __init__(self, attr, *args, **kwargs): self.attr2 = attr # 调用MRO下一个类的初始化,这里会到Base super().__init__(*args, **kwargs) class C(A, B): def __init__(self, attr1, attr2): # 按MRO顺序初始化,C→A→B→Base super().__init__(attr1, "b1", "b2", attr2) c = C(1, 2) print(c.attr1, c.attr_base1, c.attr_base2, c.attr2) # 输出 1 b1 b2 2
这种方式更符合Python的继承设计,但需要所有父类的初始化方法都配合链式调用。
内容的提问来源于stack exchange,提问作者Mr.O
相关产品推荐
相关产品推荐

