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.
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:
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 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.
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)
andE(C, B)
.So,
<class '__main__.C'>
in the second index for theE
subclass and<class '__main__.B'>
in the second index forB
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.
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.
Top comments (0)