Python class inheritance: AttributeError: '[SubClass]' object has no attribute 'xxx'
Question:
I have the following base class and subclass:
class Event:
def __init__(self, sr1=None, foobar=None):
self.sr1 = sr1
self.foobar = foobar
self.state = STATE_NON_EVENT
# Event class wrappers to provide syntatic sugar
class TypeTwoEvent(Event):
def __init__(self, level=None):
self.sr1 = level
self.state = STATE_EVENT_TWO
Further on in my code, I am inspecting an instance of a TypeTwoEvent
class, checking for a field I know exists in the base class – I expected it to be defaulted to value None
. However, my code raises the following exception:
AttributeError: ‘TypeTwoEvent’ object has no attribute ‘foobar’
I was under the impression that the base class fields would be inherited by the subclass and that creating an instance of a subclass will instantiate the base class (and thus invoke its constructor) …
What am I missing here? Why does TypeTwoEvent
not have a foobar
attribute – when the base class from which it is derived has a foobar
attribute?
Answers:
You need to call the __init__
method of the base class from the __init__
method of the inherited class.
See here for how to do this.
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).
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.
Your subclass should be:
class TypeTwoEvent(Event):
def __init__(self, level=None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.sr1 = level
self.state = STATE_EVENT_TWO
Because you override the __init__
method, so you need to call the parent method if you want the parent behavior to happen.
Remember, __init__
is not a special method dispite its strange name. It’s just the method automatically called after the object is created. Otherwise it’s an ordinary method, and ordinary inheritance rules apply.
super().__init__(arguments, that, goes, to, parents)
is the syntax to call the parent version of the method.
For *args
and **kwargs
, it just ensures we catch all additional arguments passed to __init__
and pass it to the parent method, as you child method signature didn’t do it and the parent need these arguments to work.
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.
I have the following base class and subclass:
class Event:
def __init__(self, sr1=None, foobar=None):
self.sr1 = sr1
self.foobar = foobar
self.state = STATE_NON_EVENT
# Event class wrappers to provide syntatic sugar
class TypeTwoEvent(Event):
def __init__(self, level=None):
self.sr1 = level
self.state = STATE_EVENT_TWO
Further on in my code, I am inspecting an instance of a TypeTwoEvent
class, checking for a field I know exists in the base class – I expected it to be defaulted to value None
. However, my code raises the following exception:
AttributeError: ‘TypeTwoEvent’ object has no attribute ‘foobar’
I was under the impression that the base class fields would be inherited by the subclass and that creating an instance of a subclass will instantiate the base class (and thus invoke its constructor) …
What am I missing here? Why does TypeTwoEvent
not have a foobar
attribute – when the base class from which it is derived has a foobar
attribute?
You need to call the __init__
method of the base class from the __init__
method of the inherited class.
See here for how to do this.
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).
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.
Your subclass should be:
class TypeTwoEvent(Event):
def __init__(self, level=None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.sr1 = level
self.state = STATE_EVENT_TWO
Because you override the __init__
method, so you need to call the parent method if you want the parent behavior to happen.
Remember, __init__
is not a special method dispite its strange name. It’s just the method automatically called after the object is created. Otherwise it’s an ordinary method, and ordinary inheritance rules apply.
super().__init__(arguments, that, goes, to, parents)
is the syntax to call the parent version of the method.
For *args
and **kwargs
, it just ensures we catch all additional arguments passed to __init__
and pass it to the parent method, as you child method signature didn’t do it and the parent need these arguments to work.
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.