Properties (@property) and Encapsulation
On this page
Properties as Guardrails
@property lets you expose a stable API while enforcing rules and keeping internal state consistent.
Validated Property
class Config:
def __init__(self, timeout_seconds: int) -> None:
self.timeout_seconds = timeout_seconds
@property
def timeout_seconds(self) -> int:
return self._timeout_seconds
@timeout_seconds.setter
def timeout_seconds(self, value: int) -> None:
if value <= 0:
raise ValueError("timeout_seconds must be > 0")
self._timeout_seconds = value
Operational Checklist
- Use properties for invariants that must always hold.
- Keep property logic simple; complex logic belongs in methods.
- Do not hide expensive operations behind a property (surprising call sites).
Failure Modes
- Hidden cost: property performs I/O or heavy compute unexpectedly.
- Inconsistent state: direct attribute mutation bypasses validation if not controlled.