0
0
PythonHow-ToBeginner · 3 min read

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 instance parameter in __get__, which is None when 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.

MethodPurpose
__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.