Inheritance & MRO
Python supports multiple inheritance and resolves methods with the Method Resolution Order (MRO). super() walks that order - essential for cooperative __init__ chains in mixins.
Search across all documentation pages
Python supports multiple inheritance and resolves methods with the Method Resolution Order (MRO). super() walks that order - essential for cooperative __init__ chains in mixins.
class LogMixin:
def log(self, msg: str) -> None:
print(f"[{self.__class__.__name__}] {msg}")
class Service(LogMixin):
def run(self) -> None:
self.log("starting")When to reach for this:
class Base:
def __init__(self) -> None:
self.base_init = True
class TrackingMixin:
def __init__(self, *args, **kwargs) -> None:
self.tracked = True
super().__init__(*args, **kwargs)
class TimestampMixin:
def __init__(self, *args, **kwargs) -> None:
self.timestamped = True
super().__init__(*args, **kwargs)
class Event(TrackingMixin, TimestampMixin, Base):
pass
if __name__ == "__main__":
e = Event()
print(e.tracked, e.timestamped, e.base_init)
print(Event.mro())What this demonstrates:
super().__init__ calls each class in MRO onceEvent.mro() shows resolution order for debuggingBase completes chainsuper() calls next implementation.super().__init__.HelpfulClass.mro() # list of classes in lookup order
HelpfulClass.__mro__ # tuple form# explicit override call
class Child(Parent):
def save(self) -> None:
super().save()
self.post_save_hook()super().__init__(*args, **kwargs) in mixins.__init__.| Alternative | Use When | Don't Use When |
|---|---|---|
| Composition | Has-a relationships | True is-a polymorphism |
| Protocol typing | Structural interfaces | Need shared implementation |
| Functions + dispatch | Simple behavior reuse | Template method pattern fits |
| Single inheritance | Clear hierarchy | Only need one mixin layer |
Order Python searches bases for attributes/methods. Print with Class.mro().
super() respects MRO for multiple inheritance - hardcoded parent skips cooperative mixins.
Few small ones OK. Many mixins signal design smell - consider composition.
Technically yes - watch API clarity and MRO surprises. Often composition clearer.
ABC can sit in MRO enforcing methods before concrete classes.
Call super().__init__ unless deliberately replacing whole chain - document why.
Instance attr shadows class method - descriptors and data descriptors add nuance.
Child slots must include parent slots empty declaration - complex; read docs before combining.
Assert Class.mro()[1] == ExpectedParent when mixin order critical.
Django/FastAPI patterns often subclass framework classes - follow framework docs for super calls.
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.
Reviewed by Chris St. John·Last updated Jul 16, 2026