Advanced Descriptors
Descriptor protocol, get, set, delete, and descriptors.
Overview
Master descriptor protocol.
Data Descriptors
class Validated:
def __init__(self, name, validator):
self.name = name
self.validator = validator
def __set_name__(self, owner, name):
self.name = name
def __get__(self, obj, objtype=None):
if obj is None:
return self
return getattr(obj, f'_{self.name}', None)
def __set__(self, obj, value):
if not self.validator(value):
raise ValueError(f"Invalid value for {self.name}")
setattr(obj, f'_{self.name}', value)
class Positive:
def __call__(self, value):
return isinstance(value, (int, float)) and value > 0
class User:
age = Validated("age", Positive())
user = User()
user.age = 25
print(user.age) # 25
# user.age = -5 # ValueError
Non-Data Descriptors
class Method:
def __init__(self, func):
self.func = func
def __get__(self, obj, objtype=None):
if obj is None:
return self.func
return lambda *args, **kwargs: self.func(obj, *args, **kwargs)
class MyClass:
@Method
def greet(self, name):
return f"Hello, {name}!"
obj = MyClass()
print(obj.greet("Alice")) # Hello, Alice!
Practice
Implement a caching descriptor for expensive computations.