Descriptors manage attribute access via __get__, __set__, __delete__, __set_name__.
1import logging23class LoggedAttribute:4 def __set_name__(self, owner, name):5 self.name = name6 self.private_name = f"_{name}"78 def __get__(self, obj, objtype=None):9 if obj is None:10 return self11 value = getattr(obj, self.private_name, None)12 logging.debug(f"Getting {self.name} = {value}")13 return value1415 def __set__(self, obj, value):16 logging.debug(f"Setting {self.name} = {value}")17 setattr(obj, self.private_name, value)1819 def __delete__(self, obj):20 logging.debug(f"Deleting {self.name}")21 if hasattr(obj, self.private_name):22 delattr(obj, self.private_name)2324class User:25 name = LoggedAttribute()26 email = LoggedAttribute()2728 def __init__(self, name, email):29 self.name = name30 self.email = email3132u = User("Alice", "alice@example.com")33print(u.name) # Logs: Getting name = Alice34u.name = "Bob" # Logs: Setting name = Bob
Priority rules:
property = data descriptor.