35

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?

Karl Knechtel
  • 56,349
  • 8
  • 83
  • 124
Homunculus Reticulli
  • 60,275
  • 77
  • 205
  • 314
  • 2
    As said below, you need to explicitly indicate that you want the superclasses to initialise as well. But __take care__: if you have any multiple inheritance then making this happen becomes very delicate. – Katriel Apr 22 '12 at 14:12

5 Answers5

37

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.

Karl Knechtel
  • 56,349
  • 8
  • 83
  • 124
e-satis
  • 551,433
  • 107
  • 289
  • 326
  • Thanks for the edit Chris. I'm french, and I make this confusion between "it's" and "its" quite often. Not that I mix up the meanings, but I learned the language talking, therefor it's (:-)) easy to exchange a sound for another in my head. – e-satis Apr 23 '12 at 11:12
4

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.

Karl Knechtel
  • 56,349
  • 8
  • 83
  • 124
Praveen Gollakota
  • 33,984
  • 10
  • 60
  • 61
2

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).

Chris Morgan
  • 79,487
  • 22
  • 198
  • 207
1

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.

Community
  • 1
  • 1
alan
  • 4,502
  • 20
  • 29
0

I have had problem with this also, but i've putted super().__init__() on the bottom of my derived class and that's why it doesn't work. Because i try to use attributes that is not initialized.

М.Б.
  • 1,230
  • 15
  • 20