admin管理员组文章数量:1126106
I have the following class hierarchy. The goal is for the calling code to choose either a base Foo
object or a Foobar
object that also provides the additional Bar
functionality.
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):
super().__init__(self.foo)
But when I try to run it:
>>> fb = Foobar()
AttributeError: 'Foobar' object has no attribute 'foo'
What's the right way to initialize Foobar
? I've read a number of articles and SO posts about initialization with multiple inheritance, but none where one base constructor requires a property of the other base class.
EDIT:
My actual use case is derived from /. "Bar
" is actually FigureCanvasQTAgg
and "Foobar
" corresponds to MplCanvas
. Foobar
must derive from FigureCanvasQTAgg
because the Foobar
object will be passed to a bunch of PySide6 code that uses attributes I don't know about. I'm trying to break out the regular matplotlib
code into another base class (Foo
) to I can make an alternate front end that doesn't use PySide6, but there may be a different way to achieve this goal.
EDIT 2:
Looks like the whole approach may be flawed. It would certainly be less taxing for my little brain to create foo
in a separate function before trying to instantiate either a Foo
or a Foobar
.
I have the following class hierarchy. The goal is for the calling code to choose either a base Foo
object or a Foobar
object that also provides the additional Bar
functionality.
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):
super().__init__(self.foo)
But when I try to run it:
>>> fb = Foobar()
AttributeError: 'Foobar' object has no attribute 'foo'
What's the right way to initialize Foobar
? I've read a number of articles and SO posts about initialization with multiple inheritance, but none where one base constructor requires a property of the other base class.
EDIT:
My actual use case is derived from https://www.pythonguis.com/tutorials/pyside6-plotting-matplotlib/. "Bar
" is actually FigureCanvasQTAgg
and "Foobar
" corresponds to MplCanvas
. Foobar
must derive from FigureCanvasQTAgg
because the Foobar
object will be passed to a bunch of PySide6 code that uses attributes I don't know about. I'm trying to break out the regular matplotlib
code into another base class (Foo
) to I can make an alternate front end that doesn't use PySide6, but there may be a different way to achieve this goal.
EDIT 2:
Looks like the whole approach may be flawed. It would certainly be less taxing for my little brain to create foo
in a separate function before trying to instantiate either a Foo
or a Foobar
.
3 Answers
Reset to default 1When using multiple inheritance, your classes (most of them, with maybe one exception in the while inheritance tree), have to act collaboratively. And that implies that any method on a class that knows it is not the "root base class" for that method, has to call the super version of itself - this way it ensure that when that method is called in a subclass which also have other parents, all the versions of the method are executed.
In your example, that implies that Bar.__init__
should be calling super().__init__()
, just consuming the parameters it knows about - and then FooBar.__init__()
will also call super().__init__
:
TL;DR: this is the "one obvious way to do it" - and calling any superclass method explicitly using the class name is a hack which, although can be used to circunvent some classes that doesn't have collaborative inheritance mechanisms written, should be regarded as that: temporary hacks. The fix is to make your classes collaborate in the proper way, with super()
calls.
class Foo:
def __init__(self, **kwargs):
self.foo = 'foo'
super().__init__(**kwargs)
# by also including the super() call here, you can then
# inehrit from `Foo` and `Bar` in any other.
class Bar:
def __init__(self, attr, **kwargs):
self.attr = attr
super().__init__(**kwargs)
# when "Bar" is instantiaed by itself, this call
# will call `object.__init__()`, which does nothing
# but when called from an instance with multiple inheritance
# which includes `Foo` above Bar in the __mro__,
# it will call `Foo.__init__`.
def bar(self):
# other classes aroudn don't have "bar" methods -
# so, no need to call `super().bar()`
print(self.attr + 'bar')
class Foobar(Foo, Bar):
def __init__(self, attr): # must receive all parameters that known superclasses will need!
...
super().__init__(attr=attr)
A demo for you(Just to tell why your Foobar does not have a attr
attribution, don't don't do it in real code):
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):
super().__init__() # Will use: Foo.__init__
Bar.__init__(self, self.foo)
Foobar().bar()
# foobar
I would rather do:
class Foo:
foo = "foo"
class Bar:
def __init__(self, attr) -> None:
self.attr = attr
def bar(self) -> None:
print(self.attr + "bar")
class FooBar(Foo, Bar):
def __init__(self) -> None:
super().__init__(self.foo)
FooBar().bar()
# foobar
Even though your example is not proper use of OOP, you could TECHNICALLY speaking take advantage of the fact that
__init__
methods can be called accessing them through the class (well... sort of like any method, really)- Python is interpreted and run line by line
So with that in mind you could do:
class Foobar(Foo, Bar):
def __init__(self):
Foo.__init__(self) # At this point, self has .foo
Bar.__init__(self, self.foo)
However, by looking at the clarification you posted, I would strongly recommend looking into whether I need to make my FooBar
class inherit from FigureCanvasQTAgg
or I could just have FooBar
have a FigureCanvasQTAgg
attribute. I mean: trying to split what seems to be the graphical representation provided by Matplotlib from your logic in the class.
本文标签: Python initialization with multiple inheritanceStack Overflow
版权声明:本文标题:Python initialization with multiple inheritance - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736679947a1947370.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
Foo
being an attribute rather than a base class)? – Ilya Commented Jan 9 at 1:29self.foo
wherefoo
is from the parent classFoo
beforeFoobar
has been fully initialized — hence the error. If you needFoobar
to exhibit this behaviour, why not use a singleton/factory model instead of inheritance? It seems like what you're after is composition instead of inheritance anyway. – gnome Commented Jan 9 at 1:37