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.
- Firstis- class First(B, C):
- It inherits from BandC, in that order.
- Binherits from- A.
- Cinherits from- A.
- 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 from- A.
- Binherits from- A.
- 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.