abc module
The abc module provides the building blocks for abstract base classes (ABCs) in Python. ABCs let you define a class that can’t be instantiated on its own — subclasses must provide implementations for any methods marked as abstract. It’s the standard way to enforce interface contracts in Python.
Defining an ABC
The simplest approach is to inherit from ABC:
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self) -> float:
"""Calculate and return the shape's area."""
pass
# TypeError: Can't instantiate abstract class Shape with abstract method area
# s = Shape()
A class with any abstract methods cannot be instantiated. Subclasses must implement all abstract methods before they can be instantiated.
The Two Ways to Create an ABC
Option 1 — inherit from ABC:
from abc import ABC, abstractmethod
class MyABC(ABC):
pass
Option 2 — use ABCMeta as metaclass:
from abc import ABCMeta, abstractmethod
class MyABC(metaclass=ABCMeta):
pass
Both produce the same result. Inheriting from ABC is generally cleaner.
Abstract Methods with Implementation
Unlike Java, Python’s abstract methods can have a body. When a subclass calls super(), that implementation runs — useful as an endpoint in cooperative multiple inheritance chains:
class Animal(ABC):
@abstractmethod
def speak(self) -> str:
# Abstract but has a default: subclasses must override but can call super()
return "some sound"
class Dog(Animal):
def speak(self) -> str:
return super().speak() # returns "some sound" if Dog didn't override
Abstract Properties
Stack @property with @abstractmethod for abstract read-only properties:
from abc import ABC, abstractmethod
class Container(ABC):
@property
@abstractmethod
def size(self) -> int:
"""Return the number of items in the container."""
pass
For read-write properties, mark the setter as abstract too:
class Container(ABC):
@property
def size(self) -> int:
return self._size
@size.setter
@abstractmethod
def size(self, value: int) -> None:
pass
class ListContainer(Container):
def __init__(self, items):
self._items = items
@property
def size(self) -> int:
return len(self._items)
@size.setter
def size(self, value: int) -> None:
self._items = [None] * value
Abstract classmethod and staticmethod
The decorators stack with @abstractmethod. Put @abstractmethod innermost:
class Config(ABC):
@classmethod
@abstractmethod
def from_env(cls) -> "Config":
"""Load configuration from environment variables."""
pass
@staticmethod
@abstractmethod
def validate(data: dict) -> bool:
"""Validate configuration data."""
pass
Note: abstractclassmethod and abstractstaticmethod exist but are deprecated since Python 3.3. Use the stacking approach above instead.
Virtual Subclasses with register()
You can register a class as a “virtual subclass” of an ABC without using inheritance. The issubclass() and isinstance() checks will recognize it:
from abc import ABC
class MySequence(ABC):
pass
# Register built-in tuple as a virtual subclass
MySequence.register(tuple)
issubclass(tuple, MySequence) # True
isinstance((), MySequence) # True
Virtual subclasses don’t appear in the MRO, and the ABC’s methods aren’t callable via super() on them. Only the issubclass()/isinstance() relationship is established.
Customizing issubclass with subclasshook
Override __subclasshook__ to implement custom subclass detection logic:
from abc import ABC, abstractmethod
class SupportsIter(ABC):
@abstractmethod
def __iter__(self):
pass
@classmethod
def __subclasshook__(cls, C):
if cls is SupportsIter:
# Any class with __iter__ in its MRO qualifies
if any("__iter__" in B.__dict__ for B in C.__mro__):
return True
return NotImplemented
__subclasshook__ must return True, False, or NotImplemented (which falls back to normal inheritance checks).
Dynamic Abstract Method Updates
If you modify abstract methods on a class after definition, call update_abstractmethods() to recalculate its abstraction status:
from abc import ABC, abstractmethod, update_abstractmethods
class Foo(ABC):
pass
# Dynamically add an abstract method
Fooabstractmethod = abstractmethod(lambda self: None)
Foo.__abstractmethods__ = {"my_method"}
update_abstractmethods(Foo) # Forces Python to recheck abstraction
get_cache_token
Returns a token identifying the current state of the ABC cache. The token changes whenever any ABC calls register():
from abc import get_cache_token
token = get_cache_token() # opaque object, supports equality testing
Used mainly by framework authors to detect when ABC registrations have changed.
When ABCs Beat Protocols
Use ABCs when you need:
- Explicit enforcement (can’t instantiate without implementing abstract methods)
- Virtual subclass registration (
register()) for existing classes you don’t control - Cross-module interface contracts
For general duck typing and structural subtyping (does it have __len__?), Protocol from typing is often simpler.
See Also
- isinstance() — check object types and ABC membership
- iter() — works with any ABC-derived iterable
- Protocol classes — Python’s structural subtyping via
typing.Protocol