Skip to main content
🏛️
PEP 3119 · Speedrun · Python 2.6 (2007)

PEP 3119 in 90 seconds — Abstract Base Classes and the @abstractmethod gate

A class contract that fails at construction, not at runtime.

Without ABCs, "this class must implement method X" was a comment in the README. The first time someone forgot, you found out at 2am because a `Fish.speak()` call hit a non-existent method deep in a callback. PEP 3119 (Python 2.6, 2007 — long since standard) added the `abc` module: ```python from abc import ABC, abstractmethod class Animal(ABC): @abstractmethod def speak(self): ... ``` Any subclass that doesn't override `speak()` raises `TypeError` the moment you try to instantiate it. No callback chains, no surprise NoneType errors — the error fires at construction.

ABCs also power `isinstance()` for protocol-like checks. Built-in ABCs in `collections.abc` (`Iterable`, `Iterator`, `Mapping`, `Sequence`, `Sized`, `Container`, …) let you check capability instead of concrete type: ```python from collections.abc import Sequence isinstance([1, 2, 3], Sequence) # True — lists are sequences isinstance("hi", Sequence) # True — strs are sequences too ``` It's the precursor to PEP 544 (`Protocol`) for static duck-typing. ABCs check at runtime; `Protocol` checks at type-check time.

Before — Python 2.5 / ad-hoc contract enforcement
# README says "subclasses must implement speak()" but nothing enforced it.
class Animal:
    def speak(self):
        raise NotImplementedError("subclasses must implement speak()")

class Dog(Animal):
    def speak(self):
        return "woof"

class Fish(Animal):
    pass  # forgot

# Failure only at the FIRST call — could be deep in a callback chain
Fish().speak()  # NotImplementedError, surfaces at runtime
After — Python 2.6+, ABC + @abstractmethod
from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def speak(self):
        ...

class Dog(Animal):
    def speak(self):
        return "woof"

class Fish(Animal):
    pass  # forgot — but now we catch it earlier

Dog().speak()
# Fish()    ← TypeError raised HERE, at construction, not at first call
#
# Bonus: collections.abc has ready-made ABCs you can subclass or
# isinstance-check against (Iterable, Sized, Mapping, Sequence, ...)

🎯 Predict the output

What does this print? `Fish` doesn't override `speak()`, so instantiating it raises `TypeError`.

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def speak(self): ...

class Dog(Animal):
    def speak(self):
        return "woof"

class Fish(Animal):
    pass

print(Dog().speak())
try:
    Fish()
    print("Fish instantiated (BUG)")
except TypeError:
    print("Fish: blocked — speak() not implemented")
print(issubclass(Dog, Animal))
print(isinstance(Dog(), Animal))
OOP & class design → Senior track

Or speedrun another PEP

PEP 572Assignment as an expression — 3 lines become 1.
PEP 572 in 90 seconds — the walrus that ate your for-loop
PEP 484Python stays dynamic — but you can opt into typing.
PEP 484 in 90 seconds — type hints, without TypeScript-envy
PEP 622Switch statements are a 5% feature. Pattern matching is the 95%.
PEP 622 in 90 seconds — match / case isn't just a switch