1. Multiple Inheritance in Python
A child class can inherit from more than one parent class. This is multiple inheritance. The child class inherits all attributes and methods of all classes.
class Base1:
pass
class Base2:
pass
class MultiDerived(Base1, Base2):
pass
class Person:
def info(self):
print("Info of a person.")
class Employee:
def showSalary(self):
print("Salary of an employee.")
class Teacher(Person, Employee):
pass
john = Teacher()
john.info()
john.showSalary()
Result
Info of a person.
Salary of an employee.
The Teacher class inherits from the Person and Employee classes in the above example. The Teacher class will inherit and use the info()
and showSalary()
methods from the above 2 classes.
2. Method Resolution Order (MRO) in Python
In some cases, parent classes may have methods with identical names. When a child class calls these methods, it is unclear which parent class method will be executed.
Python uses the Method Resolution Order (MRO) to determine which method is called in this case. MRO specifies one order in which class is prioritized to find and call the method first. We can use the __mro__
attribute or the mro()
function to see this order.
class Person:
def info(self):
print("Info of a person.")
def work(self):
print("A person works.")
class Employee:
def work(self):
print("An employee works.")
def showSalary(self):
print("Salary of an employee.")
class Teacher(Person, Employee):
pass
print(Teacher.__mro__)
john = Teacher()
john.work()
Result
(<class '__main__.Teacher'>, <class '__main__.Person'>, <class '__main__.Employee'>, <class 'object'>)
A person works.
In the above example, the Person class is prioritized to find the work()
method to execute first due to the inheritance order class Teacher(Person, Employee)
.
class Person:
def info(self):
print("Info of a person.")
def work(self):
print("A person works.")
class Employee:
def work(self):
print("An employee works.")
def showSalary(self):
print("Salary of an employee.")
class Teacher(Employee, Person):
pass
print(Teacher.mro())
john = Teacher()
john.work()
Result
(<class '__main__.Teacher'>, <class '__main__.Employee'>, <class '__main__.Person'>, <class 'object'>)
An employee works.
In the above example, the Employee class is prioritized to find the work()
method to execute first due to the inheritance order class Teacher(Employee, Person)
.
Note: All classes created in Python automatically inherit from the
object
class.
3. Multilevel Inheritance in Python
We can also create a new class by inheriting from a child class. This is multilevel inheritance. Python has no limit on the number of levels of inheritance.
In multilevel inheritance, the new child class inherits all the attributes and methods of both the parent and child classes.
class Base:
def methodBase(self):
print("This is a method of Base.")
class Derived1(Base):
def methodDerived1(self):
print("This is a method of Derived1.")
class Derived2(Derived1):
def methodDerived2(self):
print("This is a method of Derived2.")
# create an object of Derived2
obj = Derived2()
# call method inherits from Base
obj.methodBase()
# call method inherits from Derived1
obj.methodDerived1()
# call method of Derived2
obj.methodDerived2()
Result
This is a method of Base.
This is a method of Derived1.
This is a method of Derived2.
In the above example, the Derived1 class inherits from the Base class. The Derived2 class inherits from the Derived1 class. The Derived2 class will inherit all the attributes and methods of the Base and Derived1 classes.
4. The init() Function in Multiple Inheritance
In multiple inheritances in Python, the child class will inherit the __init__()
function of the parent classes. When creating an object of the child class, which __init__()
function will be called? As we know, Python uses the Method Resolution Order (MRO) to solve this problem. But then, there is an issue. Let’s see the following example to see this problem.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def info(self):
print(self.name + ",", self.age, "years old.")
class Employee:
def __init__(self, salary):
self.salary = salary
def showSalary(self):
print("salary:", self.salary)
class Teacher(Person, Employee):
pass
print(Teacher.mro())
john = Teacher("John", 35)
# call method inherits from Person
john.info()
# AttributeError: 'Teacher' object has no attribute 'salary'
john.showSalary()
Result
[<class '__main__.Teacher'>, <class '__main__.Person'>, <class '__main__.Employee'>, <class 'object'>]
John, 35 years old.
Traceback (most recent call last):
File "c:\python-examples\main.py", line 20, in <module>
john.showSalary()
File "c:\python-examples\main.py", line 13, in showSalary
print("salary:", self.salary)
AttributeError: 'Teacher' object has no attribute 'salary'
The issue here is that the __init__()
function used to create an object of the Teacher class is inherited from the Person class. Currently, the object has only inherited the attributes of “name” and “age” from the “Person” class. It does not have the “salary” attribute from the “Employee” class. The solution in such cases is to define the __init__()
function of the Teacher class.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def info(self):
print(self.name + ",", self.age, "years old.")
class Employee:
def __init__(self, salary):
self.salary = salary
def showSalary(self):
print("salary:", self.salary)
class Teacher(Person, Employee):
def __init__(self, name, age, salary):
super().__init__(name, age)
self.salary = salary
# create an object of Teacher with it's __init__() function
john = Teacher("John", 35, "5000000")
# call method inherits from Person
john.info()
# call method inherits from Employee
john.showSalary()
Result
John, 35 years old.
salary: 5000000
In the above example, we use the statement super().__init__(name, age)
to call the initializer of the Person class. Then, we add the salary attribute to the Teacher objects.