Introduction

Python supports multiple inheritance, which means that a child class can inherit from multiple parent classes. This feature provides enhanced flexibility and allows for the creation of complex class hierarchies. Throughout this tutorial, we will explore the fundamentals of multiple inheritance in Python, including its syntax, purpose, advantages, and potential pitfalls. By the end of this tutorial, you should have a comprehensive understanding of how to effectively implement multiple inheritance in your Python projects.

Table of Contents :

  • What is multiple inheritance
  • Implementing multiple inheritance in python
  • Calling functions of parent class
  • Invoking constructors of parent classes
  • Code Sample for multiple inheritance
  • Method Resolution Order (MRO)

What is multiple inheritance :

  • Multiple inheritance is a type of inheritance where a sub-class can inherit properties and methods from multiple super-classes.
  • It allows a sub-class to combine the features of multiple super-classes in a single class, providing flexibility in designing classes.

Implementing multiple inheritance in python

  • To create a sub-class with multiple inheritance, we simply define a new class and specify all the super-class names separated by commas within the parentheses.
  • The basic syntax of implementing multiple in python is as follows :

class A:
    # Code for parent class A

class B:
    # Code for parent class B

class C(A, B):
    # Code for child class C
    

Calling functions of parent class

  • The super() function can be used to call the methods of the super-classes 
  • In case more than one parent classes have the called method with same name then 
    • The comma separated list within the parentheses while defining the child class will be checked.
    • the method of the class that appears first in this list will be called.
  • Code Sample :

class A:
    def show(self):
        print("Show method of parent class A")


class B:
    def show(self):
        print("Show method of parent class B")


class C(A, B):
    def display(self):
        print("Display method of class C")
        super().show()
        print()


class D(B, A):
    def display(self):
        print("Display method of class D")
        super().show()
        print()


c = C()
c.display()

d = D()
d.display()


# Output
# Display method of class C
# Show method of parent class A

# Display method of class D
# Show method of parent class B


Explanation : 

  • Here classes C and D both inherit from classes A and B.
  • The only difference in their inheritance is the order of the parent classes while defining the child classes.
    • While defining class C - the order of the parent classes is kept as  (A, B) 
    • Whereas while defining class D - the order of the parent classes is kept as  (B, A) 
  • Both the classes A and B have a method with same name called  show() 
  • When object of class C calls the  show()  method using  super()  function - show method of class A is called because A appears first in the list while defining class C.
  • When object of class D calls the  show()  method using  super()  function - show method of class B is called because B appears first in the list while defining class D.

Invoking constructors of parent classes

  • We can use the name of the base class along with dot operator to invoke the  __init__  method of the base class from the child class.
  • The syntax of invoking the  __init__  method of base class is :  BaseClassName.__init__(self) 


class A(object):
    def __init__(self):
        print("Entering class A")
        print("Exiting class A")

class B(object):
    def __init__(self):
        print("Entering class B")
        print("Exiting class B")

class C(A, B):
    def __init__(self):
        print("Entering class C")
        A.__init__(self)
        B.__init__(self)
        print("Exiting class C")

C()

# Output
# Entering class C
# Entering class A
# Exiting class A
# Entering class B
# Exiting class B
# Exiting class C



Code Sample for multiple inheritance

Below we have a full working example of multiple inheritance in python


# Parent Class - 1
class Vehicle:
    def __init__(self, make, model):
        self.make = make
        self.model = model

    def show_details(self):
        print(f"The make of the Vehicle  is : {self.make}")
        print(f"The model of the Vehicle is : {self.model}")
        print()


# Parent Class - 2
class RentedVehicle:
    def __init__(self, permit_id, permit_term):
        self.permit_id = permit_id
        self.permit_term = permit_term

    def show_rent_details(self):
        print(f"The Vehicle will be used for renting purpose")
        print(f"The permit_id of the Vehicle  is : {self.permit_id}")
        print(f"The permit_term of the Vehicle is : {self.permit_term}")
        print()


# Child class
class Car(Vehicle, RentedVehicle):
    def __init__(self, make, model, utility, transmission, permit_id, permit_term):
        self.utility = utility
        self.transmission = transmission
        Vehicle.__init__(self,make, model)
        RentedVehicle.__init__(self, permit_id, permit_term)

    def show_car_details(self):
        super().show_details()
        super().show_rent_details()
        print(f"The utility of the Car is : {self.utility}")
        print(f"The transmission of the Car is : {self.transmission}")
        print()


my_car = Car("Audi", 2023, "SUV", "Automatic", "2k230101", "5 Years")
my_car.show_car_details()


# Output
# The make of the Vehicle  is : Audi
# The model of the Vehicle is : 2023

# The Vehicle will be used for renting purpose
# The permit_id of the Vehicle  is : 2k230101
# The permit_term of the Vehicle is : 5 Years

# The utility of the Car is : SUV
# The transmission of the Car is : Automatic



Method Resolution Order (MRO) :

  • In the previous section we have read that a method with same name in more than one parent classes will be called depending on the order in which the parent class appears in the comma separated list within parentheses.
  • In multiple inheritance it is quite easy to determine this order but in other type of inheritance like multilevel inheritance or hybrid inheritance it is not that straightforward. 
  • In such cases this order is determined using the Method Resolution Order (MRO) algorithm.
  • The MRO algorithm follows a Depth First Search (DFS) approach.
  • We can view the MRO for a class using the  mro()  method.
  • Code Sample :

class A:
    def show(self):
        print("Show method of parent class A")


class B:
    def show(self):
        print("Show method of parent class B")


class C(A, B):
    def display(self):
        print("Display method of class C")
        super().show()
        print()


class D(B, A):
    def display(self):
        print("Display method of class D")
        super().show()
        print()


print(C.mro())
print(D.mro())

# Output:
# [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
# [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]