python-descriptors
Table of Contents
Python descriptors
Python descriptors are objects that implement __get__, __set__, or __delete__ to intercept attribute access. They power properties, methods, static methods, and class variables—any time you access an attribute on an instance or class, the descriptor protocol may run.
Descriptors let you customize how attributes are stored, computed, validated, or accessed without explicit getter/setter function calls.
Example
This example implements a descriptor that validates and stores an age attribute.
# run: python3 descriptors.py # description: descriptor for attribute validation and storage class ValidatedInt: def __init__(self, name, min_val=0, max_val=100): self.name = name self.min_val = min_val self.max_val = max_val self.data = {} def __get__(self, obj, objtype=None): if obj is None: return self return self.data.get(id(obj)) def __set__(self, obj, value): if not isinstance(value, int): raise TypeError(f"{self.name} must be int") if not (self.min_val <= value <= self.max_val): raise ValueError(f"{self.name} must be {self.min_val}-{self.max_val}") self.data[id(obj)] = value def __delete__(self, obj): del self.data[id(obj)] class Person: age = ValidatedInt("age", 0, 150) def __init__(self, name, age): self.name = name self.age = age p = Person("Alice", 30) print(f"age: {p.age}") p.age = 31 print(f"age: {p.age}") try: p.age = 200 # raises ValueError except ValueError as e: print(f"error: {e}") try: p.age = "thirty" # raises TypeError except TypeError as e: print(f"error: {e}")
Common patterns
Data descriptors (implement __set__ or __delete__):
- Intercept all writes; take precedence over instance
__dict__ - Used for validation, computed properties, lazy loading
Non-data descriptors (only __get__):
- Don't prevent instance dict storage; instance attributes shadow them
- Used for methods, computed read-only properties
Property decorator (built-in descriptor):
@propertycreates a data descriptor for getter@attr.setter,@attr.deleteradd write/delete behavior- Cleaner syntax than manual descriptor class
Common uses:
- Validate on write (range checks, type checks)
- Lazy-load expensive data on first read
- Compute values on-the-fly without storage
- Synchronize related attributes
- Track access for logging/debugging
python-descriptors.md · Last modified: by 127.0.0.1
