MRO C3 Algorithm
Disclaimer: This is going to be Complicated!¶
Let’s figure out why this Python code raises a TypeError:
Python
¶
Python | |
---|---|
1. What is MRO and C3 Linearization?¶
- MRO stands for Method Resolution Order. It’s the sequence Python uses to look for methods or attributes in a class and its parents. For example, if
Combined
needs a method, Python follows the MRO to decide where to look first, second, and so on. - When a class inherits from multiple parents (like
First
andSecond
here), Python uses an algorithm called C3 linearization to build this sequence. It has to be consistent and make sense. - In C3, we merge lists (the MROs of the parent classes plus the list of parents) into one order. Each list has a head (the first item) and a tail (everything after the head). The rule is: Pick a head only if it’s not in any other list’s tail. If we can’t pick anything, the merge fails, and we get a
TypeError
.
2. What Are the MROs of First
and Second
?¶
let’s figure out the MROs for its parents: First
and Second
.
First
isclass First(B, C)
:- It inherits from
B
andC
, in that order. B
inherits fromA
.C
inherits fromA
.- Python starts with
First
, then follows the order of parents:B
, thenC
, thenA
(since bothB
andC
lead toA
), and finallyobject
(the ultimate base class in Python). -
So, the MRO is:
[First, B, C, A, object]
. -
Second
isclass Second(C, B)
: - It inherits from
C
andB
, in that order. C
inherits fromA
.B
inherits fromA
.- Starting with
Second
, it goesC
, thenB
, thenA
, andobject
. - So, the MRO is:
[Second, C, B, A, object]
.
Notice the difference: First
has B
before C
, while Second
has C
before B
.
3. Why Does Combined
Fail?¶
Now, Combined
is defined as class Combined(First, Second)
. Python needs to build its MRO by merging:
- The MRO of First
: [First, B, C, A, object]
- The MRO of Second
: [Second, C, B, A, object]
- The list of parents: [First, Second]
The MRO starts with Combined
, then merges these three lists using the C3 rule. Let’s do it step by step:
Starting Lists:¶
Text Only | |
---|---|
Step 1: Pick the First Item¶
- Heads:
First
(L1),Second
(L2),First
(L3). - Check
First
: - Tail of L1:
[B, C, A, object]
→ noFirst
. - Tail of L2:
[C, B, A, object]
→ noFirst
. - Tail of L3:
[Second]
→ noFirst
. First
isn’t in any tail, so pick it.- New MRO:
[Combined, First]
. - Update lists:
Step 2: Pick the Next Item¶
- Heads:
B
(L1),Second
(L2),Second
(L3). - Check
B
: - Tail of L1:
[C, A, object]
→ noB
. - Tail of L2:
[C, B, A, object]
→ hasB
. - Tail of L3:
[]
→ noB
. B
is in L2’s tail, so we can’t pick it.- Check
Second
: - Tail of L1:
[C, A, object]
→ noSecond
. - Tail of L2:
[C, B, A, object]
→ noSecond
. - Tail of L3:
[]
→ noSecond
. Second
isn’t in any tail, so pick it.- New MRO:
[Combined, First, Second]
. - Update lists:
Step 3: Pick the Next Item¶
- Heads:
B
(L1),C
(L2). (L3 is empty, so ignore it.) - Check
B
: - Tail of L1:
[C, A, object]
→ noB
. - Tail of L2:
[B, A, object]
→ hasB
. B
is in L2’s tail, so we can’t pick it.- Check
C
: - Tail of L1:
[C, A, object]
→ hasC
. - Tail of L2:
[B, A, object]
→ noC
. C
is in L1’s tail, so we can’t pick it.
Problem!¶
B
can’t be picked because it’s in L2’s tail ([B, A, object]
).C
can’t be picked because it’s in L1’s tail ([C, A, object]
).- There’s no head we can choose! The merge gets stuck.
4. Why the TypeError?¶
Python’s C3 algorithm fails when it can’t find a consistent order. Here:
- First
wants B
before C
(from [First, B, C, A, object]
).
- Second
wants C
before B
(from [Second, C, B, A, object]
).
- Combined
inherits from both, but B
and C
can’t agree on who comes first, and neither can be skipped or ignored.
Since Python can’t resolve this conflict, it raises:
Text Only | |
---|---|
Bones: Java doesn't support multiple inheritance specifically to avoid the complexity and ambiguity caused by the Diamond Problem.