Site Tools


python-descriptors

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):

  • @property creates a data descriptor for getter
  • @attr.setter, @attr.deleter add 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