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
Combinedneeds a method, Python follows the MRO to decide where to look first, second, and so on. - When a class inherits from multiple parents (like
FirstandSecondhere), 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.
Firstisclass First(B, C):- It inherits from
BandC, in that order. Binherits fromA.Cinherits fromA.- Python starts with
First, then follows the order of parents:B, thenC, thenA(since bothBandClead toA), and finallyobject(the ultimate base class in Python). -
So, the MRO is:
[First, B, C, A, object]. -
Secondisclass Second(C, B): - It inherits from
CandB, in that order. Cinherits fromA.Binherits 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. Firstisn’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. Bis 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. Secondisn’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. Bis 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. Cis in L1’s tail, so we can’t pick it.
Problem!¶
Bcan’t be picked because it’s in L2’s tail ([B, A, object]).Ccan’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.