MRO, multiple inheritance, and super()
coreadvancedA class can inherit from more than one base — class C(A, B):. The MRO (Cls.__mro__) is the single lookup path Python computes across all of them. super() walks that path, letting every class in a chain cooperate correctly.
Think of it as
The MRO is a single-file line, not a family tree — class C(A, B): does not give C two separate parents to choose between; Python flattens A, B and every one of their own bases into one ordered line (C, A, B, ..., object) and super() always means 'the next name in this line,' never 'my literal base class.' Cooperative inheritance is every class in the line agreeing to call super() and pass the baton forward, rather than any one class assuming it's the last stop.
What we're doing: Show cooperative inheritance working correctly across a diamond hierarchy — every __init__ calling super() so all three ancestor initializers run exactly once, in MRO order.
- 3
- super().__init__() in Left does not call Base directly — it calls whatever is next in Diamond's MRO, which turns out to be Right.
- 9
- Right's own super().__init__() is what actually reaches Base — MRO ensures Base runs exactly once, not twice.
- 15
- Diamond's __init__ starts the whole chain — cooperative inheritance means every class trusts the next super() call to happen.
Base init
Right init
Left init
Diamond init
(<class '__main__.Diamond'>, <class '__main__.Left'>, <class '__main__.Right'>, <class '__main__.Base'>, <class 'object'>)
TrueWhy this works: Base init prints only once, not twice, even though both Left and Right inherit from Base — this is exactly what MRO-based cooperative inheritance guarantees: C3 linearization places Base after BOTH Left and Right in Diamond's MRO, so super() calls form a single chain (Diamond → Left → Right → Base) rather than two separate branches that would run Base's __init__ redundantly. Without every class calling super(), the chain would break at whichever __init__ forgot to continue it.
Calling a parent class directly instead of super(), breaking cooperative inheritance
Wrong
Better
What you see: "Base init" prints twice for a single Diamond() call, and any setup Base performs (opening a resource, incrementing a counter) runs redundantly.
Why: Base.__init__(self) hardcodes exactly which class's __init__ runs next, completely bypassing the MRO — both Left and Right independently decide to call Base directly, so Base runs once per path instead of once total. super() instead asks 'who is next in THIS particular MRO,' which for a diamond hierarchy correctly resolves to a single shared ancestor being initialized exactly once, no matter how many subclasses lead to it.
- class C(A, B) — multiple bases
- C.__mro__ — one linear order: C, A, B, object
- super() — next name in that same order
What determines the MRO, and what super() does with it
Together
Remember: super() means "the next class in the MRO," never "my literal parent" — cooperative inheritance only works when every class in the chain calls it.
See also: inheritance · mixins · composition vs inheritance

