In your specific example, after searching B
, we can't consider Y
immediately because it is a child of A
. We can't consider Z
immediately because M
inherits from A
before it inherits from Z
.
Python uses C3 method resolution order details here .
C3 resolution order solves the diamond inheritance problem well
In the example below, we have a very generic class Object
that's a superclass of B
and C
. We only want method implementations (say of __repr__
or something) in Object
to be considered if neither B
nor C
have an implementation.
Object
/ \
B C
\ /
A
In other words, each possible parent in the transitive closure of the parent classes of A
is considered, but the classes are ordered according to the "latest" path from the base class to the class in question.
There are two paths to object
:
A -> B -> Object
A -> C -> Object
The "latest" path is A -> C -> Object
because A -> B -> Object
would be earlier in a left-biased depth-first search.
C3 linearization satisfies two key invariants:
- if
X
inherits from Y
, X
is checked before Y
.
- if
Z
inherits from U
and then V
in that order, U
is checked before V
.
Indeed C3
linearization guarantees that both of those properties hold.
It's possible to construct hierarchies that can't be linearized, in which case you get an exception at class definition time.
running inherit.py
class E: pass
class F: pass
class A(E, F): pass
class B(F, E): pass
class Z(A, B): pass
produces the following error.
Traceback (most recent call last):
File "inherit.py", line 5, in <module>
class Z(A, B): pass
TypeError: Cannot create a consistent method resolution
order (MRO) for bases E, F