Search code examples
python-3.xinheritanceinitialization

Initializing superclasses Python3


I am trying to understand when to initialize a superclass when using inheritance in python. Initially I thought that just by declaring a class inheriting from a super class, ex. class my_class(superclass):, would make available all the superclass's attributes and methods to the subclass. Which makes sense for somebody coming from Java. Then I read that Python forces us to initialize superclasses before we can implement them in our subclass, either by using the superclass.init() or super().init(). Then I came across this piece of code where I am not initializing the parent's class, however Python gave me access to the self.queue attribute from superclass without having initialized the parent class. I read the Python documentation and sometimes I think I know what they mean and some other I dont. Can anyone please explain to me when do we have to initialize superclasses in our subclasses?

class QueueError(IndexError):
pass

class Queue:
    def __init__(self):
       self.queue = []
    def put(self,elem):
       self.queue.insert(0,elem)
    def get(self):
        if len(self.queue) > 0:
            elem = self.queue[-1]
            del self.queue[-1]
            return elem
        else:
            raise QueueError

    class SuperQueue(Queue):
    def isempty(self):
        if not self.queue:
            return True
        else:
            return False

que = SuperQueue()
que.put(1)
que.put("dog")
que.put(False)
for i in range(4):
    if not que.isempty():
        print(que.get())
    else:
        print("Queue empty")

Solution

  • In general, if you override __init__ in your subclass, you should call the super __init__ method only. This is necessary if you extend the superclass. But if you want to overwrite the whole __init__, you can also omit the super call.

    Example:

    You have class A that has one attribute value1. And now you need a second attribute, so you subclass A with B and overwrite the __init__ where you call the super class (A), so A can set value1 and in B you can not set value2.
    But now you need some other attributes in C, but need the same methods as in A. So you can entirely overwrite __init__ and omit the super call to A.

    class A:
        def __init__(self, value1):
            print("Initialize A")
            self.value1 = value1
    
    
    class B(A):
        def __init__(self, value1, value2):
            super().__init__(value1)
            print("Initialize B")
            self.value2 = value2
    
    
    class C(A):
        def __init__(self, value3):
            print("Initialize C")
            self.value3 = value3
    
    
    a = A("foo")
    b = B("foo", "bar")
    c = C("baz")
    
    print(a.value1)
    print(b.value1, b.value2)
    print(c.value3)
    print(c.value1)
    

    Output

    $ python main.py
    Initialize A
    Initialize A
    Initialize B
    Initialize C
    foo
    foo bar
    baz
    Traceback (most recent call last):
      File "main.py", line 27, in <module>
        print(c.value1)
    AttributeError: 'C' object has no attribute 'value1'
    

    You can see C wasn't initialized with value1, because C didn't call A's __init__.