I have a code here:
class Prey:
def __init__(self):
super().__init__()
print("Prey's init")
class Predator:
def __init__(self):
super().__init__()
print("Predator's init")
class Rabbit(Prey):
def __init__(self):
super().__init__()
print("Rabbit's init")
class Fish(Prey, Predator):
def __init__(self):
super().__init__()
print("Fish's init")
class Hawk(Predator):
def __init__(self):
super().__init__()
print("Hawk's init")
class Creature(Rabbit, Fish, Hawk):
def __init__(self):
super().__init__()
print("Creature's init")
c = Creature()
The Relationship of the above code is here:
Prey Predator
/ \ / \
Rabbit Fish Hawk
\ | /
Creature
And the output of the above code is here:
Predator's init
Hawk's init
Prey's init
Fish's init
Rabbit's init
Creature's init
I need to understand how Method resolution Order works in python and why this specific output? (If someone have some better tutorial you can refer, please feel free to paste the link.) I have some other code which I can't paste it here, so I'm pasting here with a silly example.
The MRO is basically a linearization of a directed acyclic graph. In this case, the nodes of the graph are the classes, and a directed edge connects a class to its parent. There are no cycles, because no class can indirectly inherit from one of its own descendants. A linearization is just a fixed ordering of the classes.
An obvious constraint on this ordering is that if A
inherits from B
, then A
should appear before B
. What's less obvious is how classes not related to each other should be ordered. In order to obey a property known as monotonicity, we require (among other things) that the parents of a class be listed in the same order in the linearization as in the class definition. That is, given
class A(B, C):
...
not only does A
appear before B
and C
, but B
must appear before C
as well in a monotonic linearization.
These two facts alone are sufficient to limit our choices of a monotonic linearization in your example to
So why does Python (or rather, the C3 linearization algorithm) prefer #2 to #1? It imposes an additional constraint, based on "similarity". If A
is "more like" B
than like C
, then B
precedes C
. In this case, a Creature
is more like a Prey
than a Hawk
, because it is more like a Fish
than a Hawk
(because Fish
precedes Hawk
in the parent list), and a Fish
is kind of Prey
.