Card 05/ 08

ExampleDifficulty: Intermediate1 min

Interface Segregation in the Wild: Python's collections.abc

Sized, Iterable and Container each hold one method, and Collection combines them.

Python's standard library is built on small interfaces, and collections.abc is where you can see them. This example shows a class that implements three single-method interfaces, a class that implements one, and how Python reports each.

The module defines abstract base classes for container behaviour. Sized requires only __len__. Iterable requires only __iter__. Container requires only __contains__, the method behind the in operator. Collection combines all three, the same move as ShiftWorker combining Workable and Feedable. Python recognises these interfaces by shape: a class with __len__ counts as Sized without inheriting from it.

py
from collections.abc import Collection, Container, Iterable, Sized


class Deck:
    def __init__(self, cards):
        self.cards = list(cards)

    def __len__(self):
        return len(self.cards)

    def __iter__(self):
        return iter(self.cards)

    def __contains__(self, card):
        return card in self.cards


class Counter:
    def __len__(self):
        return 3


for value in [Deck(["A", "K", "Q"]), Counter()]:
    name = type(value).__name__
    checks = {abc.__name__: isinstance(value, abc) for abc in (Sized, Iterable, Container, Collection)}
    print(name, checks)
OutputRan with python:3.12-slim (Python 3.12.13)
Deck {'Sized': True, 'Iterable': True, 'Container': True, 'Collection': True}
Counter {'Sized': True, 'Iterable': False, 'Container': False, 'Collection': False}
A Deck with three methods, and a Counter with one, checked against four interfaces.

The Deck is all four. The Counter, which only has __len__, is Sized and nothing else, and nobody forced it to write an __iter__ it has no use for.

The design pays off in the clients. The built-in len asks only for Sized. A for loop asks only for Iterable. A function that needs to measure, loop over and test membership can ask for Collection. If the module had offered one large Container interface with every method, a class would have had to fake iteration to be measurable. This is the interface segregation principle applied by the language's own designers.