How to Create Descriptor in Python: Simple Guide
In Python, create a descriptor by defining a class with at least one of the methods
__get__, __set__, or __delete__. Then use an instance of this class as a class attribute to control attribute access on another class.Syntax
A descriptor class must define one or more of these methods:
__get__(self, instance, owner): Returns the attribute value.__set__(self, instance, value): Sets the attribute value.__delete__(self, instance): Deletes the attribute.
Use an instance of this descriptor class as a class attribute in another class to manage that attribute's behavior.
python
class Descriptor: def __get__(self, instance, owner): pass def __set__(self, instance, value): pass def __delete__(self, instance): pass class MyClass: attribute = Descriptor()
Example
This example shows a descriptor that manages a positive integer attribute. It checks the value before setting it and stores it in the instance's dictionary.
python
class PositiveNumber: def __get__(self, instance, owner): return instance.__dict__.get('_value', 0) def __set__(self, instance, value): if value < 0: raise ValueError('Value must be positive') instance.__dict__['_value'] = value def __delete__(self, instance): del instance.__dict__['_value'] class Account: balance = PositiveNumber() acc = Account() acc.balance = 100 print(acc.balance) try: acc.balance = -50 except ValueError as e: print(e)
Output
100
Value must be positive
Common Pitfalls
Common mistakes when creating descriptors include:
- Not using
instance.__dict__to store values, which can cause infinite recursion. - Forgetting to handle the
instanceparameter in__get__, which isNonewhen accessed from the class. - Not raising errors or validating values in
__set__when needed.
python
class BadDescriptor: def __get__(self, instance, owner): return self.value # Wrong: causes recursion or attribute error def __set__(self, instance, value): self.value = value # Wrong: stores on descriptor, not instance class GoodDescriptor: def __get__(self, instance, owner): if instance is None: return self return instance.__dict__.get('value', None) def __set__(self, instance, value): instance.__dict__['value'] = value
Quick Reference
Descriptor Methods:
__get__(self, instance, owner): Retrieve attribute value.__set__(self, instance, value): Set attribute value.__delete__(self, instance): Delete attribute.
Usage: Assign descriptor instance as a class attribute to control attribute access.
| Method | Purpose |
|---|---|
| __get__(self, instance, owner) | Retrieve attribute value |
| __set__(self, instance, value) | Set attribute value |
| __delete__(self, instance) | Delete attribute |
Key Takeaways
Create a descriptor by defining __get__, __set__, or __delete__ methods in a class.
Use instance.__dict__ to store attribute values inside descriptor methods to avoid recursion.
Assign the descriptor instance as a class attribute to control attribute behavior.
Handle the case when __get__ is called on the class by checking if instance is None.
Validate values in __set__ to enforce rules like type or range checks.