Abstract Base Classes — Core Concepts
The Problem ABCs Solve
Python uses duck typing: if it walks like a duck and quacks like a duck, it’s a duck. This is great for flexibility, but it means bugs hide. If you expect every plugin to implement a process() method and one doesn’t, you won’t know until that specific plugin gets called — possibly weeks into production.
Abstract Base Classes give you compile-time-ish guarantees in a dynamic language. They let you define a contract that subclasses must follow.
How It Works
The abc module provides two key tools:
ABC— a base class you inherit from@abstractmethod— a decorator that marks methods as “must implement”
When you create a class that inherits from an ABC but doesn’t implement all abstract methods, Python raises TypeError at instantiation time — not when the method is called.
This means the error happens during testing or even import, not in production at 3 AM.
The Three Patterns
1. Pure Interface
Every method is abstract. The ABC contributes no behavior — it just defines what must exist. Think of Java interfaces: the ABC says “you must have these methods” and nothing else.
2. Partial Implementation
Some methods are abstract, others are concrete. The ABC provides shared logic (like logging or validation) while requiring subclasses to implement the core behavior. This is the most common pattern in real codebases.
3. Virtual Subclassing
You can register a class as a “virtual subclass” of an ABC without inheriting from it. This is useful when you want to say “this third-party class satisfies my interface” without modifying its source code. The register() method handles this — but note that virtual subclasses don’t get the abstract method enforcement.
Built-In ABCs You Already Use
Python’s standard library is full of ABCs you interact with daily:
collections.abc.Iterable— anything with__iter__collections.abc.Mapping— dict-like objectscollections.abc.Sequence— list-like objectsnumbers.Number— numeric types
When you write isinstance(obj, Mapping), you’re checking against an ABC. This works even for classes that never explicitly inherited from Mapping — thanks to virtual subclassing and __subclasshook__.
ABCs vs Protocols
Since Python 3.8, typing.Protocol offers structural subtyping — a more flexible alternative. Protocols check “does this object have the right methods?” at type-checking time without requiring inheritance.
| Feature | ABC | Protocol |
|---|---|---|
| Requires inheritance | Yes (unless registered) | No |
| Runtime enforcement | Yes (TypeError on instantiation) | No (type checker only) |
| Can provide implementation | Yes | Yes (but unusual) |
| Best for | Internal APIs, frameworks | Type hints, third-party code |
ABCs are best when you want runtime enforcement. Protocols are best when you want static analysis flexibility.
Common Misconception
“ABCs are just for large enterprise codebases.” Not true. Any project with a plugin system, multiple backend implementations (databases, payment providers, notification services), or team-shared interfaces benefits from ABCs. Even a two-person project avoids bugs when the contract is explicit.
When to Use ABCs
- You have multiple implementations of the same interface
- Forgetting a method would cause silent failures
- You want
isinstance()checks that work across unrelated class hierarchies - You’re building a framework or library others will extend
When to Skip Them
- You have a single implementation (just use a regular class)
- You’re writing quick scripts
- Protocol-based type checking covers your needs
One thing to remember: ABCs are Python’s way of saying “I trust duck typing, but I want a safety net.” They catch the mistakes that duck typing lets slip through.
See Also
- Python Class Decorators Understand Class Decorators through an everyday analogy so Python behavior feels intuitive, not random.
- Python Composition Vs Inheritance Understand Composition Vs Inheritance through an everyday analogy so Python behavior feels intuitive, not random.
- Python Cooperative Multiple Inheritance Why Python classes can have multiple parents and still get along — like a kid learning different skills from each family member.
- Python Dataclasses Advanced Understand Dataclasses Advanced through an everyday analogy so Python behavior feels intuitive, not random.
- Python Descriptors Understand Descriptors through an everyday analogy so Python behavior feels intuitive, not random.