The contract of an ADT should not live only in documentation: we write it in code with abc.ABC or typing.Protocol, implement it on two different structures and check it with shared tests. This lesson continues ADT vs data structure in Python; the language tools themselves are covered in the lessons on abstract base classes and generics and protocols.

An abstract Stack, its two implementations and shared contract tests
An abstract Stack, its two implementations and shared contract tests

ABC: an enforced interface

The class Stack inherits from ABC and marks push, pop and __len__ as abstract. If a subclass forgets one, creating an object raises TypeError: the mistake is caught before use. Ready-made methods such as is_empty come free with every implementation.

python
from abc import ABC, abstractmethod

class Stack(ABC):
    @abstractmethod
    def push(self, x): ...

    @abstractmethod
    def pop(self): ...

    @abstractmethod
    def __len__(self): ...

    def is_empty(self):
        return len(self) == 0

class Broken(Stack):
    def push(self, x):
        pass

try:
    Broken()
except TypeError as e:
    print(type(e).__name__)
text
TypeError

Two implementations