Reputation: 68476
I have this base class and subclass:
class Event:
def __init__(self, sr1=None, foobar=None):
self.sr1 = sr1
self.foobar = foobar
# Event class wrappers to provide syntatic sugar
class TypeTwoEvent(Event):
def __init__(self, level=None):
self.sr1 = level
Later on, when I try to check the foobar
attribute of a TypeTwoEvent
instance, I get an exception. For example, testing this at the REPL:
>>> event = TypeTwoEvent()
>>> event.foobar
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'TypeTwoEvent' object has no attribute 'foobar'
I thought that the base class attributes would be inherited by the subclass and that creating an instance of a subclass would instantiate the base class (and thus invoke its constructor). Therefore, I expected the foobar
attribute value to be defaulted to None
.
Why do TypeTwoEvent
instances not have a foobar
attribute, even though Event
instances do?
Upvotes: 48
Views: 61004
Reputation: 610
None of the above fixed my problem. Apparently sometimes Python doesn't like the subclass to inherit @properties. See this screenshot:
parent_graph
used to be an @property and the same analogous error you see displayed in the picture occured. Now I made it into a regular method. So now it gets past that error and moves onto the next uninherited @property which is ambient_space
. So now you can imagine what I have to do: take away @property's in practically my whole project.
Arrow
is using single inheritance from base class Base
which in turn singly inherits from QGraphicsObject
. I am definitely calling the super().__init__()
appropriately.
Upvotes: 0
Reputation: 597291
The subclass should be:
class TypeTwoEvent(Event):
def __init__(self, level=None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.sr1 = level
Because __init__
is overridden, the base class' __init__
code will only run if it is explicitly requested.
Despite its strange name, __init__
is not specially treated. It gets called automatically after the object is created; but otherwise it's an ordinary method, and ordinary inheritance rules apply.
super().__init__(arguments, that, go, to, parents)
is the syntax to call the parent version of the method. Using *args
and **kwargs
allows us to catch additional arguments passed to __init__
and pass them to the parent method; this way, when a TypeTwoEvent
is created, a value can be specified for the foobar
, along with anything else specific to the base class.
Upvotes: 48
Reputation: 1420
I've had the same problem, but in my case I put super().__init__()
on the bottom of my derived class and that's why it doesn't work. Because I tried to use attributes that are not initialized.
Upvotes: 0
Reputation: 38990
You're overriding the constructor (__init__
) of the parent class. To extend it, you need to explicitly call the constructor of the parent with a super()
call.
class TypeTwoEvent(Event):
def __init__(self, level=None, **kwargs):
# the super call to set the attributes in the parent class
super().__init__(**kwargs)
# now, extend other attributes
self.sr1 = level
self.state = STATE_EVENT_TWO
Note that the super
call is not always at the top of the __init__
method in your sub-class. Its location depends on your situation and logic.
Upvotes: 4
Reputation: 90852
When the instance is created, its __init__
method is called. In this case, that is TypeTwoEvent.__init__
. Superclass methods will not be called automatically because that would be immensely confusing.
You should call Event.__init__(self, ...)
from TypeTwoEvent.__init__
(or use super
, but if you're not familiar with it, read up on it first so you know what you're doing).
Upvotes: 2