🚀AdvancedAdvanced Patterns
Abstract Base Classes
abc.ABC, @abstractmethod, virtual subclasses, and using ABCs for interface enforcement.
Overview
Python's `abc` module provides **Abstract Base Classes (ABCs)** a way to define interfaces that subclasses must implement. If a subclass doesn't override all `@abstractmethod` methods, instantiating it raises `TypeError`. This catches implementation errors early, at instantiation time rather than when the missing method is first called.
ABCs also support **virtual subclasses** via `ABC.register(SomeClass)` or by implementing `__subclasshook__`. This lets you declare that a class "conforms to" an interface without inheriting from it the basis of Python's duck-typing-friendly structural subtyping used in `collections.abc` (Sequence, Mapping, Iterable, etc.).
The standard library's `collections.abc` module is rich with ABCs you can inherit from or test against: `Iterable`, `Iterator`, `Sequence`, `Mapping`, `MutableMapping`, `Callable`, `Hashable`, and more. Checking `isinstance(obj, collections.abc.Mapping)` works for any dict-like object, even custom ones.
Key Points
- •Inherit from `abc.ABC` (or set `metaclass=ABCMeta`) to create an abstract class
- •`@abc.abstractmethod` marks a method as required in all concrete subclasses
- •Trying to instantiate a class with unimplemented abstract methods raises `TypeError`
- •`@abc.abstractproperty` is deprecated use `@property` combined with `@abstractmethod`
- •`ABC.register(Class)` makes Class a virtual subclass (isinstance-compatible) without real inheritance
- •`__subclasshook__(cls, C)` override for custom isinstance logic based on duck typing
- •`collections.abc` provides ready-made ABCs: Iterable, Iterator, Sequence, Mapping, Callable, etc.
Examples
Abstract base class enforcing interface
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self) -> float: ...
@abstractmethod
def perimeter(self) -> float: ...
def describe(self):
print(f"{type(self).__name__}: area={self.area():.2f}, perimeter={self.perimeter():.2f}")
class Circle(Shape):
def __init__(self, r):
self.r = r
def area(self):
import math; return math.pi * self.r ** 2
def perimeter(self):
import math; return 2 * math.pi * self.r
class Square(Shape):
def __init__(self, s):
self.s = s
def area(self): return self.s ** 2
def perimeter(self): return 4 * self.s
for s in [Circle(5), Square(4)]:
s.describe()
try:
Shape() # TypeError: Can't instantiate abstract class
except TypeError as e:
print(e)Abstract property
from abc import ABC, abstractmethod
class Animal(ABC):
@property
@abstractmethod
def sound(self) -> str: ...
def speak(self):
print(f"{type(self).__name__} says: {self.sound}")
class Dog(Animal):
@property
def sound(self):
return "Woof"
class Cat(Animal):
@property
def sound(self):
return "Meow"
Dog().speak() # Dog says: Woof
Cat().speak() # Cat says: MeowVirtual subclasses and __subclasshook__
from abc import ABC, abstractmethod
class Drawable(ABC):
@abstractmethod
def draw(self): ...
@classmethod
def __subclasshook__(cls, C):
if cls is Drawable:
if any("draw" in B.__dict__ for B in C.__mro__):
return True
return NotImplemented
class Widget:
def draw(self):
print("drawing widget")
# Widget doesn't inherit from Drawable but has draw()
print(isinstance(Widget(), Drawable)) # True (via __subclasshook__)
print(issubclass(Widget, Drawable)) # TrueCommon Mistakes
- Using `@abstractmethod` without inheriting from `ABC` or `ABCMeta` the decorator has no effect and the class can be instantiated with methods missing
- Forgetting to call `super().__init__()` in concrete subclasses skips ABC's bookkeeping
- Confusing `register()` with inheritance registered classes don't inherit any implementation from the ABC
Note
Use ABCs when you want to define a contract (interface) that multiple unrelated classes must satisfy. For internal class hierarchies, plain inheritance with `raise NotImplementedError` in base methods is often simpler and suffices.
Exercises
Write Python code to solve each exercise. Run it in your browser and check your output.
Loading editor…
Completed: 0 / 5 exercises
Knowledge Check
Question 1 of 4