Multiple inheritance and MRO in python
Your missing guide to multiple inheritance and Method Resolution Order in python.
4 min read
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.
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.
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:
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 refers to the inheritance that uses two or more base class. This is how you define multiple inheritance using
class keyword for multiple
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 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
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:
<class '__main__.C'>in the second index for the
<class '__main__.B'>in the second index for
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
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.
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
Finally, If you learned something from this article, please share it with your friends.
Did you find this article valuable?
Support Shiva Gaire by becoming a sponsor. Any amount is appreciated!