When we design a group of related classes, we often want to guarantee that every member provides the same set of methods. We could write that expectation into the documentation and hope for the best, or we could let Python enforce it for us with the abc module and its abstract base classes.
Why should we use abstract base classes?
An abstract base class defines a contract: it lists the methods a subclass must implement, without providing the implementation itself. If a subclass forgets one of them, Python refuses to create an instance and tells us why.
That moves the error from somewhere deep in production to the moment we try to use the class. It also documents the intent of our design in code, which is far harder to ignore than a comment.
Import abc
The abc module is part of the standard library, so there is nothing to install:
Create an abstract base class
We inherit from ABC and mark the required methods with the @abstractmethod decorator:
Notifier now describes what a notifier does, but it cannot do anything itself. Trying to instantiate it fails:
Implement the contract
A subclass becomes usable as soon as it implements every abstract method:
If we forget, we get the same error as before - this time for our own class:
Mix abstract and concrete methods
An abstract base class is not limited to empty methods. We can add regular methods that build on the abstract ones:
Every subclass gets send_all for free, while send stays its own responsibility.
Declare abstract properties
Attributes can be part of the contract too, by combining @property with @abstractmethod. The order matters: @property goes on top, @abstractmethod directly above the method.
A subclass can satisfy channel with a property of its own:
Python does not insist on a property, though, it only checks that the name is no longer abstract. A plain class attribute works just as well, which keeps simple subclasses short:
An instance attribute assigned in __init__ is accepted too:
And if we implement send but forget channel, we run into the familiar error before the class is ever used:
The same combination works for @classmethod, @staticmethod and property setters, so we can put any part of a class into the contract.
Conclusion
Abstract base classes give us a cheap way to turn an informal agreement between classes into something Python checks for us. They cost a single decorator and a base class, and in return we get clear intent, early failures, and helpful error messages. Whenever we find ourselves writing "every subclass has to implement this", abc is the tool we are looking for.
Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.