Exercises — Multiple inheritance — Python's C3 linearization algorithm
Recall The one rule you need, restated
, base case .
Merge: take the head of the first list; it is a good head if it appears in no tail (any position after position 0) of any list. If good, emit it and delete it everywhere; if not, try the head of the next list. If no good head exists → TypeError.
Throughout, means object.

Level 1 — Recognition
Exercise 1.1
Given class A: pass, what is ?
Recall Solution
WHAT: Apply the base rule. A has no explicit parents, so its only parent is object.
Answer: [A, object].
Exercise 1.2
For class B(A) with class A, is this single or multiple inheritance, and what is ?
Recall Solution
WHAT: One direct parent → Single inheritance. C3 on a single chain just stacks the parent's MRO under the child.
Answer: single inheritance; [B, A, object].
Exercise 1.3
In the merge of merge([B, A, O], [C, A, O], [B, C]), is B a good head of the first list?
Recall Solution
WHAT: Check whether B appears in the tail of any list. Tails: [A,O], [A,O], [C]. B is in none of them.
Answer: Yes — B is a good head, so it is emitted first.
Level 2 — Application
Exercise 2.1 — the classic diamond
class A, class B(A), class C(A), class D(B, C). Compute by hand.
Recall Solution
Precompute: , .
| Iter | Lists | Try | Good? | Reason |
|---|---|---|---|---|
| 1 | [B,A,O] [C,A,O] [B,C] |
B |
✅ | not in any tail |
| 2 | [A,O] [C,A,O] [C] |
A |
❌ | A in tail of list 2 → try C ✅ |
| 3 | [A,O] [A,O] [] |
A |
✅ | now in no tail |
| 4 | [O] [O] [] |
O |
✅ |
Answer: [D, B, C, A, object].
Exercise 2.2 — asymmetric depth
class A, class B(A), class C(B), class D(A), class E(C, D). Compute .
Recall Solution
Precompute: , , , .
| Iter | Lists | Try | Good? | Reason |
|---|---|---|---|---|
| 1 | [C,B,A,O] [D,A,O] [C,D] |
C |
✅ | not in any tail |
| 2 | [B,A,O] [D,A,O] [D] |
B |
✅ | not in any tail |
| 3 | [A,O] [D,A,O] [D] |
A |
❌ | A in tail of list 2 → try D ✅ |
| 4 | [A,O] [A,O] [] |
A |
✅ | now in no tail |
| 5 | [O] [O] [] |
O |
✅ |
Answer: [E, C, B, A, D, O]... wait — recheck iter 3: after emitting B, D becomes a good head before A because A is still blocked. So the order is E, C, B, D, A, O.
Let me re-lay iter 3 cleanly: lists are [A,O] [D,A,O] [D]. Head of list 1 is A, blocked (in tail of list 2). Head of list 2 is D, in no tail → emit D. Lists become [A,O] [A,O] []. Then A, then O.
Answer: [E, C, B, D, A, object].
Exercise 2.3 — three parents, flat
class A, class B, class C, class D(A, B, C). Compute .
Recall Solution
Each of A,B,C is [X,O].
A not in any tail → emit. Then B (tail-free) → emit. Then C → emit. Then O.
Answer: [D, A, B, C, object] — the written parent order is preserved, and O sinks to the bottom.
Level 3 — Analysis
Exercise 3.1 — spot the inconsistency
class X, class Y, class A(X, Y), class B(Y, X), class C(A, B). Does exist? If not, name the exact contradiction.
Recall Solution
, .
Emit A (tail-free). Lists: [X,Y,O] [B,Y,X,O] [B]. Try X: in tail of list 2 → skip. Try B: tail-free → emit. Lists: [X,Y,O] [Y,X,O] []. Try X: in tail of list 2 (Y,X,O) → skip. Try Y: in tail of list 1 (X,Y,O) → skip. No good head.
Answer: No valid MRO. Contradiction: A demands X before Y; B demands Y before X. Python raises TypeError: Cannot create a consistent method resolution order (MRO).
Exercise 3.2 — reverse-engineer a super() jump
For D(B, C), B(A), C(A) (MRO [D,B,C,A,O]), a method in B calls super().m(). Which class's m runs next?
Recall Solution
WHAT: super() walks the MRO of the instance's type, not B's literal parent. In L[D], the successor of B is C.
Answer: C.m runs — even though B's written parent is A. This is the cooperative behaviour covered in super() and cooperative inheritance.
Exercise 3.3 — monotonicity check
Given L[B]=[B,A,O], is it possible for any subclass of B to have an MRO in which A comes before B?
Recall Solution
WHAT: Monotonicity says relative order in a parent's MRO is never reversed in a subclass. Since B precedes A in , no subclass may put A first.
Answer: Impossible — and a child always precedes its parents anyway, so B before A is doubly guaranteed.
Level 4 — Synthesis
Exercise 4.1 — design to a target MRO
You want a class E whose MRO is exactly [E, M1, M2, Base, object], where M1, M2 are Mixins and Base is the concrete class. Write the class headers (parent lists) that produce this, and verify by hand.
Recall Solution
Design: class Base, class M1, class M2, class E(M1, M2, Base).
Each mixin/base is [X,O].
Emit M1, then M2, then Base, then O.
Answer: class E(M1, M2, Base): ... → [E, M1, M2, Base, object]. (List mixins before the concrete base so their overrides win — a standard Mixins pattern.)
Exercise 4.2 — build a valid deep hierarchy
Construct classes so that of the bottom class is [G, E, F, B, C, D, A, object]. One valid design plus its verification.
Recall Solution
Design: A; B(A), C(A), D(A); E(B, C), F(C, D); G(E, F).
Precompute: B=[B,A,O], C=[C,A,O], D=[D,A,O],
E=[E,B,C,A,O], F=[F,C,D,A,O].
Emit E → B → then C blocked (tail of list 2) so try list 2 head F → emit F → now C free → C → D → A → O.
Answer: [G, E, F, B, C, D, A, object]. ✅ (Note F jumps ahead of B... let's confirm: after E, lists [B,C,A,O] [F,C,D,A,O] [F]; B tail-free → emit B; lists [C,A,O] [F,C,D,A,O] [F]; C blocked (tail of list 2) → try F, tail-free → emit F; then C, D, A, O. Order emitted: E,B,F,C,D,A. So the real MRO is [G, E, B, F, C, D, A, object].)
Corrected answer: the design above yields [G, E, B, F, C, D, A, object]. To get B after F you would need F listed to force it — but C3 keeps B right after E here. Trust the merge, not the guess.
Level 5 — Mastery
Exercise 5.1 — predict, then explain the whole chain
class A, class B(A), class C(A), class D(B, C), class E(D, C). Compute and state whether class E(C, D) (parents swapped) would still be valid.
Recall Solution
, .
Emit D (tail-free). Lists: [B,C,A,O] [C,A,O] [C]. B tail-free → emit. Lists: [C,A,O] [C,A,O] [C]. C tail-free (its only tails are [A,O]) → emit. Then A, then O.
Answer: [E, D, B, C, A, object].
Swap E(C, D): now the parent list is [C,D]. But already places D before C (as D's own... actually D before C inside L[D]), while E(C,D) demands C before D. Conflict → TypeError. So order matters: E(D, C) works, E(C, D) fails.
Exercise 5.2 — full trace with a print check
For the classes in Ex 5.1, at runtime E().__mro__ should match your hand result. Write the expected tuple exactly.
Recall Solution
Answer: (<class 'E'>, <class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>) — i.e. [E, D, B, C, A, object], confirming Ex 5.1. This is a constrained Topological sort: every child precedes its parents, and no two ancestors' orders were reversed.
Connections
- Method Resolution Order
- super() and cooperative inheritance
- The Diamond Problem
- Single inheritance
- Mixins
- Composition vs Inheritance
- Topological sort