Why this matters
Inheritance is the obvious solution when you need to add behavior — until you need combinations. A coffee shop with Espresso, Milk, Sugar, and Caramel can produce 16 combinations. Subclassing gives you 16 classes. Adding Vanilla makes it 32. The Decorator pattern escapes this explosion: each wrapper implements the same interface and holds a reference to another instance of that interface. You stack decorators like LEGO bricks — unlimited combinations from a small set of parts.
The problem
Bad
The solution
Good
In the wild
Python's own @functools.wraps, logging handlers, and middleware stacks all use the Decorator pattern. Django and FastAPI middleware layers are decorators. The pattern is also the foundation of Python's @decorator syntax, though function decorators are a simpler variant that wraps callables rather than objects.
Key takeaway
If you're creating subclasses for every combination of features, use Decorator. Prefer composition over inheritance — a handful of decorators unlocks more combinations than any class hierarchy.