28 · Inheritance and super()
Build class hierarchies with class Child(Parent), call parent code with super(), understand the MRO, and learn when to prefer composition over deep inheritance.
`class Child(Parent):` means "Child **is a** Parent, plus extra". The child inherits every method and attribute of the parent. `super().__init__(...)` delegates to the parent's `__init__` so you don't duplicate setup code. Python resolves method lookup through the **Method Resolution Order (MRO)** — a left-to-right, depth-first search that handles multiple inheritance correctly.
Without this:
Without inheritance you'd copy `.fit()` and `.predict()` into every estimator class. The entire sklearn taxonomy — `BaseEstimator`, `ClassifierMixin`, `RegressorMixin` — relies on inheritance to share dozens of utility methods across hundreds of models.
Inheritance lets a class reuse and extend the behaviour of another. The parent (base) class holds the shared implementation; each child (derived) class inherits it and can override methods — replacing the parent's version by defining a method with the same name.
super() gives you a proxy to the parent class. Calling super().__init__(...) inside a child's __init__ runs the parent's initialiser so you don't have to duplicate the attribute setup. You can similarly call super().method_name(...) to run the parent's version of any overridden method — useful when you want to extend rather than replace behaviour.
Multiple inheritance (class D(B, C):) is allowed in Python. When the same method name appears in multiple parents, Python uses the C3 linearisation algorithm to build a deterministic MRO (Method Resolution Order). ClassName.__mro__ or help(ClassName) shows you the full resolution chain — worth checking whenever you see surprising method binding. The general advice: favour composition (a model HAS-A scaler) over deep inheritance hierarchies (a model IS-A scaler IS-A estimator IS-A ...) — deep hierarchies become hard to understand and debug.
Python (in browser)
`super().__init__(name)` and `super().fit(X, y)` are the two most common uses of `super()`. Without `super().__init__()`, the child's `__init__` would have to duplicate all the parent's attribute setup — and any future changes to the parent's `__init__` would need to be mirrored manually.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
The MRO for `D` is `[D, B, C, A, object]`. When `B.hello` calls `super().hello()`, Python looks up the MRO from `B`'s position — the next class is `C`, not `A`. This is why the diamond outputs `"B -> C -> A"` and not `"B -> A"`. Understanding MRO prevents mysterious "wrong method was called" bugs in multi-inherit hierarchies.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Every PyTorch model inherits from `nn.Module`. The `super().__init__()` call is mandatory — it wires up the internal parameter registry that tracks gradients. You override `forward()` (the parent declares it but expects you to replace it) and call the model as a function: `output = model(x)` invokes `__call__`, which wraps `forward`.
What does `super().__init__()` do inside a child class's `__init__`?
- `class Child(Parent):` inherits everything from `Parent`. Override a method by redefining it; call the parent's version with `super().method_name(...)`.
- `super().__init__(...)` runs the parent's `__init__` on the current instance — always call it first in child `__init__` unless you have a deliberate reason not to.
- Python's MRO (`ClassName.__mro__`) defines method resolution order for multiple inheritance. Prefer composition over deep inheritance hierarchies in production ML code.
Every PyTorch model inherits from `nn.Module` — `super().__init__()` is the first line of every `__init__`. Sklearn uses `BaseEstimator` + mixin classes (`ClassifierMixin`, `RegressorMixin`) to inject `get_params`, `set_params`, `score`, and other utilities via multiple inheritance. LightGBM and XGBoost wrap their C++ models in Python classes that inherit from `BaseEstimator` so they slot into sklearn pipelines without modification.
If you remove it: Without inheritance, every model would re-implement `get_params`, `set_params`, `clone`, and `score` from scratch — thousands of lines of duplicated utility code across the sklearn ecosystem alone.