31 · Abstract base classes with abc
Declare a contract that subclasses must fulfil — if they don't implement every @abstractmethod, Python refuses to instantiate them.
`from abc import ABC, abstractmethod` lets you declare a **contract class** that cannot be instantiated directly. Any method decorated with `@abstractmethod` **must** be overridden by every concrete subclass — Python enforces this at instantiation time with a `TypeError`.
Without this:
Without ABCs, a subclass that forgets to implement `.predict()` passes silently until the missing method is called at runtime — often deep inside a training loop. ABCs move the error to instantiation time, making the contract explicit and the bug immediately visible.
abc.ABC (Abstract Base Class) is a helper base class that enables the @abstractmethod decorator to enforce contracts. When you write class BaseModel(ABC): and decorate methods with @abstractmethod, Python marks those methods as requirements. Any attempt to instantiate BaseModel() directly raises TypeError: Can't instantiate abstract class. Subclasses that implement all abstract methods can be instantiated normally.
This pattern is the formal way to define an interface in Python — the difference from duck typing is that violations are caught at object creation rather than at the first missing method call.
typing.Protocol (Python 3.8+) is the structural alternative: you declare the expected method signatures without requiring inheritance. Type checkers verify conformance statically; no runtime enforcement. Choose ABC when you want runtime enforcement and shared implementation (the ABC can have concrete methods too — only @abstractmethod ones are required). Choose Protocol when you want duck-typing-friendly static analysis.
Python (in browser)
`BaseModel` has two abstract methods (requirements) and one concrete method (`score`) that subclasses inherit for free. The `...` (ellipsis) in abstract methods is the conventional body — it's never called directly.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
The error message names every unimplemented abstract method — making it easy to know exactly what a subclass is missing. This fires at `BaseModel()` construction time, not later when `.fit()` would have been called.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`MajorityClassifier` implements both `fit` and `predict`, so it instantiates cleanly. It also inherits `.score()` from `BaseModel` for free — that's the ABC pattern: enforce the contract, share free utilities.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
With `Protocol`, the type checker verifies conformance without requiring `class MyModel(ModelProtocol)`. This is **structural subtyping** vs. ABC's **nominal subtyping**. Use ABC when you want shared code + runtime enforcement; use Protocol when you're integrating with external libraries that can't inherit from your ABC.
Can you instantiate `BaseModel()` directly if it inherits from `ABC` and has `@abstractmethod` methods?
- `class MyABC(ABC):` + `@abstractmethod` creates a contract class. Python raises `TypeError` at instantiation time if any abstract method is missing — the error names every unimplemented method.
- ABCs can also have concrete methods — shared utilities subclasses inherit for free. Only `@abstractmethod` methods are requirements.
- ABC = nominal subtyping + runtime enforcement + shared code. `typing.Protocol` = structural subtyping + static enforcement only (no inheritance required).
Sklearn's `BaseEstimator` provides parameter introspection and cloning for free to every model that inherits it. `ClassifierMixin.score()` and `RegressorMixin.score()` are concrete ABC methods that provide accuracy/R² automatically. PyTorch's `nn.Module` raises `NotImplementedError` from `forward()` — an informal ABC pattern. OpenAI Gym / Gymnasium defines `Env` with abstract `reset()` and `step()` that every environment must implement.
If you remove it: Without ABCs, a missing `.predict()` in a custom sklearn-compatible estimator goes undetected until a pipeline step calls it — deep inside a cross-validation loop, far from the class definition. ABCs surface this error immediately on object construction.