Python多继承类初始化问题:如何正确初始化依赖另一基类属性的Foobar子类
首先,咱们先拆解下你代码报错的核心原因:当你在Foobar的__init__里写super().__init__(self.foo)时,self.foo根本还没被创建出来!因为此时Foo类的初始化逻辑还没执行,self对象还没经过Foo的初始化流程,自然没有foo这个属性。而且这里的super()调用也不符合你的需求——Python多继承里的super()是按MRO(方法解析顺序)来调用下一个类的方法,Foobar的MRO是Foobar → Foo → Bar → object,所以super().__init__会先调用Foo的__init__,但Foo的__init__不需要参数,你传了self.foo本身就会引发参数不匹配的错误,更别说这个属性还不存在了。
那正确的初始化方式应该是先显式完成Foo的初始化,拿到需要的属性后,再显式初始化Bar,直接调用两个基类的__init__方法并传入self:
class Foo: def __init__(self): self.foo = 'foo' class Bar: def __init__(self, attr): self.attr = attr def bar(self): print(self.attr + 'bar') class Foobar(Foo, Bar): def __init__(self): # 先初始化Foo,给self添加foo属性 Foo.__init__(self) # 再用已存在的self.foo初始化Bar Bar.__init__(self, self.foo)
测试一下这个代码:
>>> fb = Foobar() >>> fb.bar() foobar
完全可以正常运行,不会再出现属性错误。
结合你的实际使用场景聊聊
你提到Bar实际是FigureCanvasQTAgg,Foobar对应MplCanvas,想把Matplotlib的逻辑抽到Foo类里,方便做非PySide的前端。这个思路没问题,调整后的初始化逻辑也完全适用:
- 让
Foo负责创建Matplotlib的Figure对象(对应示例里的self.foo); Foobar先初始化Foo拿到figure,再把figure传给FigureCanvasQTAgg的__init__(因为FigureCanvasQTAgg的构造确实需要一个Figure实例)。
关于你后来想到的替代方案
你说把foo的创建放到单独函数里,再实例化Foo或Foobar,这个思路也非常合理!这样可以彻底避开多继承初始化的依赖问题,代码逻辑会更直观,比如:
def create_figure(): # 实际这里是创建Matplotlib Figure的逻辑 return 'foo' # 单独使用Foo fig = create_figure() foo_obj = Foo() foo_obj.foo = fig # 使用Foobar fig = create_figure() fb_obj = Foobar() fb_obj.foo = fig # 也可以把create_figure()直接写到Foobar的__init__里
这种方式对新手更友好,也减少了多继承带来的复杂度,如果你觉得这样更省心,完全可以采用这个方案。
备注:内容来源于stack exchange,提问作者Ilya

