We are going to learn about python multiple inheritance today. Before starting multiple inheritance, I suggest you to skim through Python Class and Python Inheritance if you are not familiar with them.
Python Multiple Inheritance
The name says it all. One class extending more than one class is called multiple inheritance. This is one of the cool specialties of python which makes it more convenient than java in some cases (Java doesn’t support multiple inheritance). Java doesn’t have it because at times multiple inheritance may create some ambiguity. We shall talk about it later in this tutorial.
Multiple Inheritance vs Multi-level Inheritance
It may seem confusing if you are familiar with multi-level inheritance before. The main difference between multiple and multi-level inheritance is that, in multi-level inheritance the superclass may also inherit another super class. And in this way, different levels of inheritance can be created among the classes.
Python Multiple Inheritance Example
Let’s demonstrate a short example of python multiple inheritance.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#definition of the class starts here class Person: #defining constructor def __init__(self, personName, personAge): self.name = personName self.age = personAge #defining class methods def showName(self): print(self.name) def showAge(self): print(self.age) #end of class definition # defining another class class Student: # Person is the def __init__(self, studentId): self.studentId = studentId def getId(self): return self.studentId class Resident(Person, Student): # extends both Person and Student class def __init__(self, name, age, id): Person.__init__(self, name, age) Student.__init__(self, id) # Create an object of the subclass resident1 = Resident('John', 30, '102') resident1.showName() print(resident1.getId()) |
The classes Person and Student are superclass here and Resident is the subclass. The class Resident extends both Person and Student to inherit the properties of both classes. The example is easily understandable if you have the slightest knowledge of python class and python inheritance. This code yields the following output.
1 2 3 4 5 6 |
/usr/bin/python3.5 "/home/imtiaz/PycharmProjects/python tutorial - 1/multiple_inheritance.py" John 102 Process finished with exit code 0 |
Resolving the Conflicts with python multiple inheritance
Let’s have a look at another example.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class A: def __init__(self): self.name="John" self.age = 23 def getName(self): return self.name class B: def __init__(self): self.name="Richard" self.id = '32' def getName(self): return self.name class C(A, B): def __init__(self): A.__init__(self) B.__init__(self) def getName(self): return self.name C1 = C() print(C1.getName()) |
Class C inherits both A and B. And both of them has an attribute ‘name’. From which class the value of name will be inherited in C? Is it from A or B? What do you think? Well, the output is:
1 2 3 4 5 |
/usr/bin/python3.5 "/home/imtiaz/PycharmProjects/python tutorial - 1/multiple_inheritance.py" Richard Process finished with exit code 0 |
The name when printed is ‘Richard’ instead of ‘John’. Let’s try to understand what’s happening here. In the constructor of C, the first constructor called is the one of A. So, the value of name in C becomes same as the value of name in A. But after that, when the constructor of B is called, the value of name in C is overwritten by the value of name in B. So, the name attribute of C retains the value ‘Richard’ when printed. The result would be same even if we declared class C as:
1 2 3 |
Class C(B, A): |
The hierarchy becomes completely depended on the order of __init__() calls inside the subclass. To deal with it perfectly, there is a protocol named MRO (Method Resolution Order).
Method Resolution Order (MRO)
Let’s replace the previous code with a slightly modified version.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
class A: def __init__(self): super().__init__() self.name="John" self.age = 23 def getName(self): return self.name class B: def __init__(self): super().__init__() self.name="Richard" self.id = '32' def getName(self): return self.name class C(A, B): def __init__(self): super().__init__() def getName(self): return self.name C1 = C() print(C1.getName()) |
Can you guess the output? Well, let’s find out.
1 2 3 4 5 |
/usr/bin/python3.5 "/home/imtiaz/PycharmProjects/python tutorial - 1/multiple_inheritance.py" John Process finished with exit code 0 |
MRO works in a depth first left to right way. super() in the __init__ method indicates the class that is in the next hierarchy. At first the the super() of C indicates A. Then super in the constructor of A searches for its superclass. If it doesn’t find any, it executes the rest of the code and returns. So the order in which constructors are called here is:
C -> A -> B
If we call print(C.__mro__), then we can see the MRO traceroute.
1 2 3 |
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>) |
Once the constructor of A is called and attribute ‘name’ is accessed, it doesn’t access the attribute ‘name’ in B. A better understanding of MRO is a must in order to work with python multiple inheritance.
So this was it for python multiple inheritance, hope to come with more interesting features of python afterwards. Happy Coding!
Reference: Python Doc