Descriptors implement __get__, __set__, __delete__ to manage attribute access. Decorators like @property use descriptors internally.
1class Validated:2 def __init__(self, min_val=None, max_val=None):3 self.min_val = min_val4 self.max_val = max_val56 def __set_name__(self, owner, name):7 self.name = name89 def __get__(self, obj, objtype=None):10 if obj is None:11 return self12 return obj.__dict__.get(self.name)1314 def __set__(self, obj, value):15 if self.min_val is not None and value < self.min_val:16 raise ValueError(f"{self.name} must be >= {self.min_val}")17 if self.max_val is not None and value > self.max_val:18 raise ValueError(f"{self.name} must be <= {self.max_val}")19 obj.__dict__[self.name] = value2021class Product:22 price = Validated(min_val=0)23 quantity = Validated(min_val=0, max_val=1000)2425p = Product()26p.price = 100 # OK27# p.price = -10 # ValueError!
Built-in descriptors:
property — getter/setter.classmethod — class method.staticmethod — static method.super() — cooperative inheritance.