__get__, __set__, __delete__
Pyyhkäise näyttääksesi valikon
A descriptor is any object that defines at least one of three special methods: __get__, __set__, or __delete__. When an instance of such an object is assigned as a class attribute, Python's attribute lookup machinery calls these methods automatically instead of returning the object directly.
The Three Methods
__get__(self, obj, objtype=None) is called when the attribute is read. obj is the instance accessing the attribute (None when accessed from the class). objtype is the class:
12345678910111213# A minimal read-only descriptor class Descriptor: def __get__(self, obj, objtype=None): if obj is None: return self # Accessed from the class – return the descriptor itself return f"Value accessed on {obj.__class__.__name__}" class Report: status = Descriptor() # Descriptor assigned as a class attribute report = Report() print(report.status) # "Value accessed on Report" print(Report.status) # The Descriptor object itself
__set__(self, obj, value) is called when the attribute is written:
1234567891011121314151617181920212223242526# A descriptor that validates and stores a value class PositiveNumber: def __set_name__(self, owner, name): self._name = name # Storing the attribute name for error messages def __get__(self, obj, objtype=None): if obj is None: return self return obj.__dict__.get(self._name) def __set__(self, obj, value): if not isinstance(value, (int, float)) or value <= 0: raise ValueError(f"{self._name} must be a positive number, got {value!r}") obj.__dict__[self._name] = value class Product: price = PositiveNumber() def __init__(self, name, price): self.name = name self.price = price # Triggers __set__ laptop = Product("ThinkPad", 1200.0) print(laptop.price) # 1200.0 laptop.price = -50 # Raises ValueError
__delete__(self, obj) is called when the attribute is deleted with del:
1234567891011121314151617181920212223242526272829# Adding deletion support to the descriptor class PositiveNumber: def __set_name__(self, owner, name): self._name = name def __get__(self, obj, objtype=None): if obj is None: return self return obj.__dict__.get(self._name) def __set__(self, obj, value): if not isinstance(value, (int, float)) or value <= 0: raise ValueError(f"{self._name} must be a positive number, got {value!r}") obj.__dict__[self._name] = value def __delete__(self, obj): obj.__dict__.pop(self._name, None) print(f"{self._name} removed from {obj!r}") class Product: price = PositiveNumber() def __init__(self, name, price): self.name = name self.price = price laptop = Product("ThinkPad", 1200.0) del laptop.price # Triggers __delete__ print(laptop.__dict__) # {'name': 'ThinkPad'}
__set_name__
__set_name__(self, owner, name) is called automatically when the descriptor is assigned to a class attribute. It gives the descriptor access to its own attribute name without hardcoding it:
1234567891011121314151617# __set_name__ receives the class and attribute name at class creation time class TrackedAttribute: def __set_name__(self, owner, name): print(f"Descriptor assigned to {owner.__name__}.{name}") self._name = name def __get__(self, obj, objtype=None): if obj is None: return self return obj.__dict__.get(self._name) def __set__(self, obj, value): obj.__dict__[self._name] = value class Invoice: amount = TrackedAttribute() # Prints: Descriptor assigned to Invoice.amount currency = TrackedAttribute() # Prints: Descriptor assigned to Invoice.currency
Kiitos palautteestasi!
Kysy tekoälyä
Kysy tekoälyä
Kysy mitä tahansa tai kokeile jotakin ehdotetuista kysymyksistä aloittaaksesi keskustelumme