Descriptors Basics (How @property Works)
On this page
What a Descriptor Is
A descriptor is an object that customizes attribute access via __get__, __set__, or __delete__. Properties are descriptors.
Minimal Descriptor
class PositiveInt:
def __set_name__(self, owner, name):
self.private_name = "_" + name
def __get__(self, obj, objtype=None):
return getattr(obj, self.private_name)
def __set__(self, obj, value):
if not isinstance(value, int) or value <= 0:
raise ValueError("must be a positive int")
setattr(obj, self.private_name, value)
class Config:
timeout_seconds = PositiveInt()
def __init__(self, timeout_seconds: int) -> None:
self.timeout_seconds = timeout_seconds
Operational Checklist
- Use descriptors when you need reusable, cross-field validation logic.
- Keep descriptor logic small and deterministic (no I/O).
- Prefer clarity: properties are enough for most cases.
Failure Modes
- Hidden behavior: complex descriptors make debugging harder.
- Unexpected side effects: attribute access triggers expensive work.