Method Resolution Order in Python 3
In this article, I am going to explain what is Method Resolution Order( MRO) and why we need it.
In python 3, every class is inherited from the base class object.
class A(object):
pass
or
class A:
pass
Both are the same in python 3.
Multiple inheritances: When a class inherits the characteristics of more than one class. Ex.
class A(object):
def __init__(self):
print('class A')
class B(object):
def __init__(self):
print('class B')
class C(A, B):
def __init__(self):
print('class C')
super().__init__()
obj1 = C()
This creates the famous diamond problem.
In the above example, the object class is the SuperClass. In what order the classes are going to inherit? So what this code is going to print?
Here comes, MRO. MRO is used primarily to obtain the order in which methods should be inherited in the presence of multiple inheritances. Python 3 uses the C3 linearization algorithm for MRO.
Linearization of class C
L[C] = C + merge of linearization of parents of C and list of parents of C in the order they are inherited from left to right.
Where L[C] represents the list in which order C is going to provoke the method of superclasses.
In the above example
L[C] = C + merge( L[A], L[B], AB)
L[A] = A + merge(L[O], O) # the linearization of object base class( O) is trivially the singleton list, i.e O itself.
L[A] = AO
L[B] = BO # Same procedure as L[A]
so L[C] = C + merge( AO, BO, AB)
Now how to calculate the merge? To calculate merge follow these steps.
Step 1:- Take the head of the first list.
Step 2:- If this head is not in the tail of any other lists then add it to the linearization of C and remove all of its instances from the lists in the merge. Otherwise, look at the head of the next list and take it if it is a good head.
Step 3:- Then repeat the operation until all the classes are removed or it is impossible to find a good head.
Now L[C] = C + merge( AO, BO, AB)
L[C] = CA+ merge( O, BO, B) # head = A
L[C] = CAB+ merge( O, O) # head = B
L[C] = CABO # head =O
So code shall print
class C
class A
You may have noticed that super is just invoking the method of the superclass in an order in which they are inherited left to right in this case (A, B). So super will first search for the method in A if not found then in B.
It may seem that C3 is not useful for this example but rather makes things more complicated. But it shall be handy for a complex hybrid inheritance. Let’s take a look at this example.
class F(O):passclass E(O):passclass D(O):passclass C(D,F):passclass B(D,E):passclass A(B,C):pass
Where O is the base object class.
What is L[A]? It’s tough to predict directly.
Let’s go step by step.
L[A] = A + merge (L[B], L[C], BC)
We need L[B] and L[C] to calculate this.
L[B] = B + merge( DO, EO, DE)
L[B] = BD+ merge( O, EO, E) # head =D
L[B] = BD + merge( O, EO, E) # head =O, not a good head
L[B] = BDE + merge( O, O) # head =E
L[B] =BDEO # head =O
and
L[C] = C + merge( DO, FO, DF)
L[C] = CD + merge( O, FO, F) # head=D
L[C] = CD+ merge( O, FO, F) # head=O, not a good head
L[C] = CDF+ merge( O, O ) # head=F
L[C]= CDFO # head =O
So now substituting L[B] and L[C]
L[A] = A +merge( BDEO, CDFO, BC)
L[A] = AB +merge( DEO, CDFO, C) # head =B
L[A] = AB +merge( DEO, CDFO, C) # head =D, not a good head because it is in tail of CDFO
L[A] = ABC +merge( DEO, DFO) # head =C
L[A] = ABCD +merge( EO, FO) # head =D
L[A] = ABCDE +merge( O, FO) # head =E
L[A] = ABCDEF +merge( O, O) # head =F
L[A] = ABCDEFO # head =O
So MRO is A->B->C->D->E->F->O
C3 provides a solution only when a monotonic order exists.
If you just want to know MRO, use
classname.mro()
This is my first article, any feedback would be greatly appreciated. Thank you.