In this tutorial, we’ll describe the Python Multiple Inheritance concept and explain how to use it in your programs. We’ll also cover multilevel inheritance, the super() function, and focus on the method resolution order.
Understand Multiple Inheritance in Python
In the previous tutorial, we have gone through Python class and Python (single) Inheritance. You must have noticed that always a child class inherits from a base class. However, Multiple Inheritance is a feature where a class can derive attributes and methods from many base classes.
Hence, it creates a high level of complexity and ambiguity and is known as the diamond problem in the technical world. We’ll be taking up this problem later in this tutorial.
A general perception of Multiple Inheritance is that it is either “dangerous” or “bad.” Also, Java doesn’t allow Multiple Inheritance, while C++ does have it. However, Python lays down a mature and well-designed approach to address multiple Inheritance.
Let’s now try to understand the topic in detail. Please go through each section carefully to understand these OOP concepts inside out.
What is Multiple Inheritance?
When you inherit a child class from more than one base class, that situation is known as Multiple Inheritance. It, however, exhibits the same behavior as does the single inheritance.
The syntax for Multiple Inheritance is also similar to the single inheritance.
By the way, in Multiple Inheritance, the child class claims the properties and methods of all the parent classes.
Basic Python Multiple Inheritance Example
""" Desc: Python program to demonstrate the diamond problem (a.k.a. Multiple Inheritance) """ # Parent class 1 class TeamMember(object): def __init__(self, name, uid): self.name = name self.uid = uid # Parent class 2 class Worker(object): def __init__(self, pay, jobtitle): self.pay = pay self.jobtitle = jobtitle # Deriving a child class from the two parent classes class TeamLeader(TeamMember, Worker): def __init__(self, name, uid, pay, jobtitle, exp): self.exp = exp TeamMember.__init__(self, name, uid) Worker.__init__(self, pay, jobtitle) print("Name: {}, Pay: {}, Exp: {}".format(self.name, self.pay, self.exp)) TL = TeamLeader('Jake', 10001, 250000, 'Scrum Master', 5)
The output is:
Name: Jake, Pay: 250000, Exp: 5
Overriding Methods Example
When you define a parent class method in the child, then this process is called Overriding.
In other words, a child class can override the methods of its parent or superclass by defining a function with the same name.
However, there are some rules for overriding:
- The name of the method should be the same and its parameters as well.
- If the superclass method is private (prefixed with double underscores), then you can’t override it.
In Python, you can use the super() method for overriding. It has the following syntax:
# Override using the super() method super(class_name, self).override_method_name()
Check the below example.
""" Desc: Python program to demonstrate overriding using the super() method """ class base(object): def base_func(self): print('Method of base class') class child(base): def base_func(self): print('Method of child class') super(child, self).base_func() class next_child(child): def base_func(self): print('Method of next_child class') super(next_child, self).base_func() obj = next_child() obj.base_func()
The result is:
Method of next_child class Method of child class Method of base class
What is Multi-level Inheritance?
When you inherit a class from a derived class, then it’s called multilevel inheritance. And, it can go up to any level in Python.
In multilevel inheritance, properties of the parent and the child classes are available to the new class.
Multilevel inheritance is akin to the relationship between grandpa, father, and child. You can sense it in the below examples.
- A car derives from the vehicle, which itself belongs to the automobile class.
- An inverter AC is a subclass of the AC class, which relates to the Appliance superclass.
Below is a simple illustration depicting the multilevel inheritance.
class parent: pass class child(parent): pass class next_child(child): pass
You can observe the following by looking at the above code:
- The child class is a derivative of the parent.
- The next_child class is a derivative of the child.
Python Multi-level Inheritance Example
""" Desc: Python program to demonstrate multilevel inheritance """ class Team: def show_Team(self): print("This is our Team:") # Testing class inherited from Team class Testing(Team): TestingName = "" def show_Testing(self): print(self.TestingName) # Dev class inherited from Team class Dev(Team): DevName = "" def show_Dev(self): print(self.DevName) # Sprint class inherited from Testing and Dev classes class Sprint(Testing, Dev): def show_parent(self): print("Testing :", self.TestingName) print("Dev :", self.DevName) s1 = Sprint() # Object of Sprint class s1.TestingName = "James" s1.DevName = "Barter" s1.show_Team() s1.show_parent()
The output is:
This is our Team: Testing : James Dev : Barter
Python Multiple vs. Multi-level Inheritance
The primary differences between Multiple and Multilevel Inheritance are as follows:
- Multiple Inheritance denotes a scenario when a class derives from more than one base class.
- Multilevel Inheritance means a class derives from a subclass making that subclass a parent for the new class.
- Multiple Inheritance is more complex and hence not used widely.
- Multilevel Inheritance is a more typical case and hence used frequently.
- Multiple Inheritance has two classes in the hierarchy, i.e., a base class and its subclass.
- Multilevel Inheritance requires three levels of classes, i.e., a base class, an intermediate class, and a subclass.
Method Resolution Order (MRO)
Method Resolution Order (MRO) is an approach that a programming language takes to resolve the variables or methods of a class.
Python has a built-in base class named as the object. So, any other in-built or user-defined class that you define will eventually inherit from it.
Now, let’s talk about how the method resolution order (MRO) takes place in Python.
- In the multiple inheritance use case, the attribute is first looked up in the current class. If it fails, then the next place to search is in the parent class, and so on.
- If there are multiple parent classes, then the preference order is depth-first followed by a left-right path, i.e., DLR.
- MRO ensures that a class always precedes its parents and for multiple parents, keeps the order as the tuple of base classes.
Basic MRO Example
""" Desc: Python program to demonstrate how MRO resolves a method or an attribute """ class Heap: def create(self): print(" Creating Heap") class Node(Heap): def create(self): print(" Creating Node") node = Node() node.create()
Here is the result:
Creating Node
MRO Example with Multiple Inheritance
""" Desc: Python program to demonstrate how MRO works in multiple inheritance """ class Agile: def create(self): print(" Forming class Agile") class Dev(Agile): def create(self): print(" Forming class Dev") class QA(Agile): def create(self): print(" Forming class QA") # Ordering of classes class Sprint(Dev, QA): pass sprint = Sprint() sprint.create()
Here is the output:
Forming class Dev
In this example, we showcased the Multiple Inheritance, known as Diamond inheritance or Deadly Diamond of Death.
Methods for Method Resolution Order(MRO)
You can check the Method Resolution Order of a class. Python provides a __mro__ attribute and the mro() method. With these, you can get the resolution order.
See the below example:
""" Desc: Python program to demonstrate how to get MRO using __mro__ and mro() """ class Appliance: def create(self): print(" Creating class Appliance") class AC: def create(self): print(" Creating class AC") # Oder of classes class InverterAC(Appliance, AC): def __init__(self): print("Constructing InverterAC") appl = InverterAC() # Display the lookup order print(InverterAC.__mro__) print(InverterAC.mro())
The result is:
Constructing InverterAC (<class '__main__.InverterAC'>, <class '__main__.Appliance'>, <class '__main__.AC'>, <class 'object'>) [<class '__main__.InverterAC'>, <class '__main__.Appliance'>, <class '__main__.AC'>, <class 'object'>
Built-in Inheritance Methods in Python
Python gives us two built-in methods to check inheritance. Here, they are:
a. isinstance()
The isinstance()
function tests an object type. It returns True or False accordingly.
# Syntax isinstance(object, class)
Check the below example:
# Python issubclass() example num = 1.0 print("Is the number {} of float class type? {}".format(num, isinstance(num, float)))
Here is the result:
Is the number 1.0 of float class type? True
b. issubclass()
The issubclass()
function tests if a particular class inherits another class or not. It has the following syntax:
# Syntax issubclass(child_class, parent_class)
It results in True if the given class is actually derived from the parent or returns False otherwise.
""" Desc: Python program to showcase issubclass() """ class parent(): def __init__(self, x): self.x = x class child(parent): def __init__(self, x, y): self.y = y parent.__init__(self, x) print("Is the child derived from the parent class? {}".format(issubclass(child, parent)))
The result is as follows:
Is the child derived from the parent class? True
Python Objects and Classes – Quiz
Do a quick self-assessment of your Python OOP skills.
After wrapping up this tutorial, you should feel comfortable using Python Multiple Inheritance. However, we’ve provided enough examples to practice more and gain confidence.