Phase 8 of 25 · Topic 8.4

Descriptor Protocol (__get__, __set__, __delete__)

1Concept

A Descriptor is an object attribute with 'binding behavior' defined by the Descriptor protocol: `__get__()`, `__set__()`, and `__delete__()`. Descriptors power Python's properties, bound methods, `classmethod`, and ORM database columns.

2Architecture Diagram

Attribute Access (obj.age) ---> Intercepted by Descriptor.__get__()
Attribute Assign (obj.age = 25) ---> Intercepted by Descriptor.__set__()

3Code Example

Python 3.12
class PositiveInteger:
    def __init__(self, name: str):
        self.name = name

    def __get__(self, instance, owner):
        if instance is None: return self
        return instance.__dict__.get(self.name, 0)

    def __set__(self, instance, value):
        if not isinstance(value, int) or value <= 0:
            raise ValueError(f"{self.name} must be a positive integer!")
        instance.__dict__[self.name] = value

class ProductInventory:
    stock_count = PositiveInteger("stock_count")

p = ProductInventory()
p.stock_count = 50
print(f"Validated Stock Count: {p.stock_count}")

try:
    p.stock_count = -10
except ValueError as e:
    print(f"Descriptor Validation Blocked: {e}")

4Expected Output

Validated Stock Count: 50
Descriptor Validation Blocked: stock_count must be a positive integer!

5Key Takeaways

  • Data Descriptors implement `__set__` or `__delete__` and take precedence over instance `__dict__`.
  • Non-Data Descriptors implement only `__get__` (e.g. standard methods).
  • Use `__set_name__(self, owner, name)` (PEP 487) to capture field names automatically.