Python Multiple Inheritance

Filed Under: Python

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 vs multi-level inheritance

Python Multiple Inheritance Example

Let’s demonstrate a short example of python multiple inheritance.


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


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


		
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:


/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:


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.


		
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.


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


(<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

Comments

  1. A friend says:

    @srini
    You can call super().__init__(name, age) but you would have to modify your __init in your A class to accept the age parameter only to be able to pass it to the second parent class __init__. Also add super.().__init__(age) to class A, this will pass age to class B.
    Also you need to add super().__init__() in your parent classes, otherwise parent B __init__ never gets calles, check MRO rules online.
    It is doable but will make your code ugly, stick to separate calles as sugested by the author

  2. srini says:

    Hi Pankaj,

    In the above example, the initializer is not taking input from the C’s instance.
    Incase if i wish to initialize the parent constructors from child class instance, how should i use the super() to initialize.

    example.

    class A:
    def __init__(self, name):
    self.name = name
    def getName(self):
    return self,name

    class B:
    def __init__(self, age):
    self.age = age
    def getAge(self):
    return self.age

    class C(A, B):
    def __init__(self, name, age, mobile):
    # how to use super() to initialize both of my parent classes?
    # super().__init__(name), followed by another super().__init__(age) initializing only name variable not age variable
    Any idea?

    1. Pankaj says:

      Use A.__init__() and B.__init__(), I don’t think we can use super() in this case.

      1. A friend says:

        @Pankaj, you can if u add *args, and **kw to all __init__ and super().__init__(), so that it won’t care about the number of args

  3. chakri says:

    Hi All,

    I have a question related to multiple inheritance, kindly help

    Here is my sample code
    class Animal():
    ”’ This is the base class”’
    def __init__(self):
    print(“I am animal”)
    def who_am_i(self):
    print(“Animal class”)
    class Dog(Animal):
    ”’ This is subclass inheriting parent class ”’
    def __init__(self):
    print(“This is init of Dog class”)
    def who_am_i(self):
    print(“This is from Dog class and not from Animal class”)

    class Cat(Dog):
    ”’This is the class inheriting subclass ”’
    pass
    myanimal = Animal()
    mydog = Dog()
    mycat = Cat()

    When I call the method
    mycat.who_am_i()
    I will get the output “This is from Dog class and not from Animal class”

    Is there a way to print “Animal Class” by calling mycat object.
    Please help me, thanks in advance

  4. Rakesh Kumar M says:

    Hi ,

    I agree of the mro prints (, , , ).

    when i added a print statement to all __init__ method of classes i am seeing a different output which i am not able to understand. please find the below code with output.

    class A:
    def __init__(self):
    super().__init__()
    print(“class A”)
    self.name = ‘John’
    self.age = 23

    class B:
    def __init__(self):
    super().__init__()
    print(“class B”)
    self.name = ‘Richard’
    self.id = ’32’

    class C(A, B):
    def __init__(self):
    super().__init__()
    print(“class C”)

    def getName(self):
    return self.name

    C1 = C()
    print(C1.getName())
    print(C.__mro__)

    output is as below :
    class B
    class A
    class C
    John
    (, , , )

    when the class order is C > A > B why the init method of B is getting invoked. please let me know if i misunderstood something.

    Thanks

  5. Your example and comments are very helpful indeed. The only point that needs to be cleared I think is that the order of execution of __init__ calls and the order of resolution of MRO for the getName() call is the same. Is that correct ? For that purpose I have added print statements at the BEGINNING of each __init__ to reveal the order in which constructors are called when you create an instance of C class.

  6. Nadia Ansari says:

    That was really helpful. Can you please provide a tutorial on multi level inheritance?

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages