Multiple inheritance and MRO in python
Tags: python, python3, beginners, tutorial
Published: 2021-05-24 06:13:29

---
title: Multiple inheritance and MRO in python
published: true
description: Your missing guide to multiple inheritance and Method Resolution Order in python.
tags: #python , #python3 , #beginners  #tutorial
cover_image: https://cdn.hashnode.com/res/hashnode/image/upload/v1621796311448/Qu5EN9Ctc.jpeg?w=1600&h=840&fit=crop&crop=entropy&auto=compress
canonical_url: https://dev.shivagaire.com.np/multiple-inheritance-and-mro-in-python
---

# Introduction
Let's first talk about the word **inheritance**, oxford dictionary defines it as *[something from the past or from your family that affects the way you behave, look, etc.](https://www.oxfordlearnersdictionaries.com/definition/american_english/inheritance)*

In object-oriented programming, inheritance facilitates code reuse with the primary motivation of reusing or extending the parent or base class in children or subclass, hence the subclass or children class is affected by the parent class. It however provides freedom to children class to modify the parent's attributes and methods.



## Inheritance
Let's see an example which is most common in all paradigm, here `Children` class inherits from `Parent` class and inherits some methods of `Parent` class and also overrides the `Parent` class implementation:

```python
class Parent():
    def parent_function(self):
        print("parent_function")
    
    def common_function(self):
        print("Parent's common_function")


class Children(Parent):
    def child_function(self):
        print("Child's child_function")
    
    def common_function(self):
        print("Child's common_function")

if __name__ == "__main__":
    child = Children()
    parent = Parent()

    parent.parent_function() # #prints 'parent_function'
     
    child.child_function()  #prints 'child's function'
    child.parent_function() #prints 'parent_function'
    
    # common of both
    parent.common_function() #prints "Parent's common_function"
    child.common_function() #prints "Child's common_function"
    
``` 
This type of single inheritance is common across all Object-Oriented Paradigm, However, Python has something more to offer with multiple inheritance, which means you can inherit from multiple base classes.

## Multiple Inheritance
Multiple Inheritance refers to the inheritance that uses two or more base class. This is how you define multiple inheritance using `class` keyword for multiple `baseClass`:  
>`class SubClass(baseClass, baseClass2, baseClass3, ....)`
 
Python has its renowned multiple inheritance feature which comes in handy when working with a class that needs implementation from two or more class.


When working with multiple base class there arises confusion if one or more base class implements the same method. Let's see how this is handled in python in next step: 

## Method Resolution Order

Multiple inheritance can create confusion when there are one or more base classes that implement the same method. Python(2.3 and newer) version introduced the renowned `method resolution order` or `mro` to deal with the method resolution while using multiple inheritance. 

Method resolution order(MRO) in short has its root in  [C3 linearization algorithm](https://en.wikipedia.org/wiki/C3_linearization) which basically outlines the basis for MRO list calculation in python multilevel inheritance. Method Resolution Order is the python provided calculation of inheritance graph. 

The MRO calculation has 3 major points to consider for the method resolution list from a subclass. 

- Subclasses comes first rather than the base classes
- Base class definition order is preserved
- Fits the above two criteria for all MRO calculation in a program

If this is violated then C3 prohibits the python from inheritance declaration. 

Let's see an example to see the `mro` list.


```python
class A():
    def __init__(self):
        print("Hi from A")
    
class B(A):
    def __init__(self):
        print("Hi From B")

class C(A):
    def __init__(self):
        print("Hi from C")

class D(B, C):
    pass
class E(C, B):
    pass


print(D.__mro__) 
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
print(E.__mro__) 
# ((<class '__main__.E'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>))

``` 

We use the `__mro__` attribute often pronounced as `dun~der mro` (double underscore mro) with class name, It gives the tuple of classes defining the method's resolution order for the subclass.

In the above example, we can see the diamond inheritance formation. So, on printing  `D.__mro__` attribute,  it gives:
> `(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)`

and on printing `E.__mro__` , it gives: 
>`(<class '__main__.E'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)`


> Notice the difference in the second element of the above tuple, its because the base class order is preserved for the class definition of class D and E:  **`D(B, C) ` and `E(C, B)`**.  

>So, `<class '__main__.C'>` in the second index for the `E` subclass and `<class '__main__.B'>` in the second index for `B` subclass.

The method resolution order will be entirely based on the above tuple order,  
which means when any method is invoked for the instance of class `D`, the method of class `D` will be resolved first and if not found it will try to resolve from the second element from the `D.__mro__` tuple , which is class `B` and so on to the next element, if no such method is implemented it will result in `AttributeError`.

If the implementation is found for the current lookup the search stops right there and the method will be resolved from there. 

If you made it upto here, Please come up in discussion to check the `__mro__` for the below snippet.

```python
class A():
    def __init__(self):
        print("Hi from A")
    
class B(A):
    def __init__(self):
        print("Hi From B")

class C(A):
    def __init__(self):
        print("Hi from C")

class D(B, A, C):
    pass
```
Why?


> Finally, If you learned something from this article, please share it with your friends.

> You may also follow me on  [LinkedIn](https://www.linkedin.com/in/geeksambhu/)  and  [Twitter](https://twitter.com/geeksambhu)