PyPuzzle 004 Method Resolution Order
This weeks PyPuzzle will test your knowledge of the Method Resolution Order (MRO) and the C3 linearisation algorithm that determines the order in which classes are inherited and methods are resolved.
- Inheritance and method resolution
- Method Resolution Order (MRO)
- The
super()
function
Feel free to use an online Python compiler and interpreter like [this] (https://www.online-python.com/) to try running the code yourself. The answer is supplied below the code.
Question
What is the expected output of the following code?
class A:
def show(self):
print("A")
class B(A):
def show(self):
print("B")
super().show()
class C(A):
def show(self):
print("C")
super().show()
class D(B, C):
def show(self):
print("D")
super().show()
d = D()
d.show()
Hints
- Python uses the C3 linearization algorithm to determine the MRO of a class. What does the MRO look like for
D
? - The
super()
function doesn’t always refer to the immediate parent class. Instead, it follows the MRO. - How do multiple inheritance and
super()
calls interact?
Answer
The output is:
D
B
C
A
- MRO (Method Resolution Order): The MRO for class
D
is determined using the C3 linearization algorithm. The MRO forD
is:[D, B, C, A]
. - When
d.show()
is called:-
D.show()
is executed first and printsD
. It then callssuper().show()
, which refers to the next class in the MRO,B
. -
B.show()
is called and printsB
. It also callssuper().show()
, which refers toC
, the next in the MRO. -
C.show()
is executed and printsC
. It callssuper().show()
, which moves toA
. -
A.show()
is executed and printsA
. SinceA
doesn’t have asuper().show()
call, the chain ends there.
-
Learnings
- Method Resolution Order (MRO): The MRO determines the order in which classes are checked when a method is called. It is calculated using the C3 linearization algorithm, which ensures that the inheritance hierarchy is respected without ambiguity. Note that the MRO is unique for each class yet the MRO of a subclass is still consistent with the MRO of its parent class.
The MRO of a class can be checked with the __mro__
attribute or the mro()
method.
class A:
pass
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
print(D.__mro__)
# Output: (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
- C3 Linearisation Algorithm: This algorithm determines the MRO for each class. It works by merging the MROs of the direct parent classes and the list of parent classes themselves. The C3 linearisation algorithm follows the following principles:
- Preserve the local precedence order: If a class
B
inherits from a classA
,B
should appear beforeA
in the MRO for classB
(and any other classes that inherit from classB
). - Consistent across all subclasses: The algorithm should work uniformly when building MROs of classes that have common ancestors.
- Avoid duplicate entries: Each class should appear only once in the MRO.
- Preserve the local precedence order: If a class
-
super()
: Thesuper()
function doesn’t necessarily refer to the immediate parent class but instead follows the MRO. This is crucial in cases of multiple inheritance. - Class Hierarchies: Understanding how Python resolves method calls in complex hierarchies can prevent unexpected behavior and bugs in class designs involving multiple inheritance.
Enjoy Reading This Article?
Here are some more articles you might like to read next: