P28 · Objects & Data Modelling

classes, dataclasses, the data model & protocols

Data modelling and contracts for serious Python: dataclasses done right, protocols versus inheritance, and abstract base classes as designed interfaces.

A dataclass is not a shorter way to write __init__. Used deliberately, it is where you decide which objects are allowed to exist at all — and that decision is worth more than any amount of downstream validation, because a check you remember to perform is a check someone will eventually forget. This pillar is about designing types whose invalid states cannot be constructed, and contracts that a checker rather than a convention holds callers to.

The first track models the data. Dataclasses with the options that matter — frozen for immutability where mutation buys nothing, ordering and comparison where they are meaningful, defaults that do not silently share state — and validation placed at construction, so an instance that exists is an instance you can trust. The second track handles the interface between components, and it turns on a distinction Python supports in both directions. Structural typing says anything with the right shape qualifies, which is what a Protocol expresses and what lets you accept objects from code you do not control, tests included. Nominal typing says a class must declare its intent by inheriting, which is what an abstract base class expresses and what lets you refuse accidental conformance. Neither is the default answer; the track is about knowing which question you are in.

Shapedataclasses, frozen, defaultsValidateat construction, not laterStructuralProtocol, anything shaped rightNominalABC, declared intent
Model so invalid states cannot exist, then choose the contract that matches who implements it.
P28 · Objects & Data Modelling — TransformerLab