Python Representation Invariants
definitions
python
representation-invariants
assertions
A representation invariant is a condition or property that must remain true about an object’s internal state throughout its lifetime. They’re primarily a development-time tool: they help catch bugs early, simplify method implementations (since you can assume a valid starting state), and document the assumptions a class relies on.
Documenting invariants
State invariants in the class docstring, underneath its attributes:
class Fraction():
"""Represents a mathematical fraction.
Representation Invariants:
- denominator != 0
- if fraction is zero, it is represented as 0/1
"""
Enforcing invariants
Assertions
assert <condition that should be true>, "message if it's not"
- Raises
AssertionErrorif the condition is false. - Disabled when Python is run with optimization (
python -O) — so asserts should catch bugs, not perform real input validation that must always run (useraise ValueError(...)etc. for that).
The _check_invariants() helper pattern
Centralise all invariant checks in one private method, and call it:
- At the end of
__init__. - At the end of any method that mutates state.
- At the start of any method that relies on the invariants already holding.
def _check_invariants(self) -> None:
assert self._denom != 0, "Denominator cannot be zero."
...
Encapsulation: don’t expose mutable internals
Returning a direct reference to a private mutable attribute (like a list or dict) lets external code silently violate the class’s invariants:
def get_members(self): # BAD -- exposes the real list
return self._members
def get_members(self): # GOOD -- caller gets an independent copy
return list(self._members)
Best practices
- Document invariants in docstrings.
- Centralise invariant checking in a single method.
- Don’t expose methods/attributes that could let external code violate invariants.
- Write test cases that target edge cases.
- Type hints can express some invariants, but not all (e.g. numeric ranges still need explicit checks).
- Balance strictness with practicality — not every property needs an assertion.