Tricky yet easy to understand, plethora of use cases though
In the previous article, I had touched upon the basic implementation of the OOPs concept of Inheritance in Python. The article also touched upon the idea of super() function.
In this notebook, I have dived a bit into depths of super(), MULTIPLE Inheritance and function OVER-RIDING.
Take a deep breath and Brace youselves, get ready to dive into Inheritance. Happy Inheritance (:
realpython.com, Thanks again for some thoughtful insights.
Ideology of MULTIPLE INHERITANCE
In simple inheritance, we have ONE CHILD class inheriting information from ONE PARENT CLASS. It is a 1 to 1 relation. But in case of INHERITANCE, ONE CHILD class inherits information from TWO OR MORE PARENT classes.
Pictorially, this is how they look. The left link, represents SIMPLE Inheritance while the right link merge represents MULTIPLE Inheritance.
What is super()
Now, with the fundamental understanding of what inheritance, how it is implemented in Python (at least simple one) and the difference between SIMPLE and MULTIPLE inheritance, I strongly feel, you are in a good state to understand, what super() actually is ?
From a broader perspective, at a higher level, super() gives you access to methods in a superclass from the subclass that inherits from it.
super() without any appended functionalities returns a temporary object of the SUPER class (also known as PARENT class). This temporary object can then be used to call the methods of the SUPER class.
This is similar to the procedure of accessing the methods belonging to a class outside the class using .; here instead <super()>. is used to call the respective SUPER class of the CHILD class from within the CHILD class.
super() in SIMPLE Inheritance
SUPER and CHILD Class Definition
To understand this, let us consider a bunch of classes, where the ‘square’ class inherits from the ‘polygon’ class. Here, ‘polygon’ class is the SUPER class whereas ‘square’ class is the CHILD class. The code block below contains the definitions of SUPER and CHILD classes.
What is the super() doing ?
In Line 41, the ‘square’ class definition above has an init() that has two parameters. First one ‘self’ is a pointer that points to the class itself. The next one is another parameter ‘sides’. Nothing new, just like any other init().
In Line 42, the expression, another init() is mentioned, but this time, this is a function call prefixed by super() through DOT notation.
We know that, super() returns the temporary object of the SUPER class of the CHILD class from where it is getting called. In this case, super() is called from ‘square’ class which is inherited from ‘polygon’ class. The expression in Line 42, calls the init() of the ‘polygon’ class. And correspondingly, we also need to ensure the correct arguments are supplied in line with SUPER class’s init() parameter definition.
super() is not restricted to just the init(), it can be used to call any method of the SUPER class from within the CHILD class
Simple, right ?? Now let us intialise the ‘square’ class and see what is happening.
More on super()
Until now, we have been using super() parameter-less.
Well, it can take two optional parameters, the CHILD class whose SUPER class we are trying to reach and a pointer to the CHILD class itself.
super() can also be used to reach the higher PARENT classes by skipping levels.
To understand this better, let me define a SIMPLE Inheritance of 3 classes in sequence. This is also known as MULTI-LEVEL Inheritance
The ‘child’ class defined above is inherited from ‘parent’ which is inherited from ‘grand_parent’.
super() can also be used to call the gprnt_method() from grand_parent class. This can be achieved by passing ‘parent’ as the class name within the super()
This is handy when one of the methods of a higher level class is over-ridden in any of its child classes, but we want to access the pre-over ridden version of the method. Let us discuss one last concept of “method OVER-RIDING” before we go ahead and understand MULTIPLE Inheritance
As name says, the concept is about overriding the method defined in a PARENT class through a child class.
What just happened here ???
‘child’class already has a child_method(). On definig a new method with same, the method of the SUPER Class gets overridden. Here, child_method defined inside the childs_child class overrides the orignal method defined in the ‘child’ class. Be careful, on doing this, any update done to the PARENT class method will not reflect for this over riding CHILD class and its downstream CHILD classes.
Bottom line, if super(,) is used, it will go ahead and call the method corresponding to the PARENT of this CHILD.
And, finally, we are here, the last topic, Congratulations for making this far ;-)
As we had already discussed, in MULTIPLE inheritance, MUTLIPLE PARENTS share all their information to ONE CHILD.
Let us use a dummy set of classes to understand this.
Well, well, well, what did I just do in the code block above. Unfortunately, MULTIPLE INHERITANCE is slightly tricky. Unlike, SIMPLE inheritance, which has just one PARENT, using super() was pretty straightforward. But in case of MULTIPLE inheritance, we have multiple PARENTs. super() will follow what the METHOD RESOLUTION ORDER (MRO) says. MRO is just a list of classes that Python will refer when it comes across two methods with same name. And we all know, to initialize a class, we all use a class with the same name init()
By default, Python interpreter gives priorities in the sequence of PARENT class definition in the inheritance statement. See line 3 of the code block above. The ‘child’ class takes ‘mother’ as the FIRST PARENT class and ‘father’ as the SECOND PARENT class. Hence, the parameter-less super() will end up initialising the init() of ‘mother’ class.
Okay, but how I have mutliple parents here, what do I do to initialise the other PARENTS. super() with arguments comes to the rescue here. Just define super() with the PARENT class and its pointer itself as arguments which has already been initialised.
When any new classes are defined, all these are by default objects of the main SUPER class. Literally all the classes have some default PARENT. Once this is done, the interpreter will go and look for the next available init() in the main SUPER class which would be nothing but the second PARENT’s init(). Let us not get too much into this for now. Similarly, if the CHLD class has many parents, write super() statements by keeping on updating the argument CLASS name in sequential expressions.
Be careful, the same issue will pop up for all the methods. A good code should ensure, redundant names should not be used for the features of classes which are related to each other some way. In that case, the MRO will not affect us, only one method with the specified identifier will exist in the code.
Exection of MUTLIPLE Inheritance
Method Resolution Order (MRO)
Some additional reading material on MULTIPLE INHERITANCE for the curious ones
As always, stackoverflow to the rescue.
Happy Coding, Happy Inheritance :)
The code is available in my Github repository.