Python – Descriptors
In Python, controlling how attributes are accessed, modified, or deleted is very powerful in advanced object-oriented programming.
This is where Descriptors come in.
Descriptors allow you to define custom behavior for:
- Getting attribute values
- Setting attribute values
- Deleting attributes
They are used internally in Python for properties, methods, and class attributes.
What is a Descriptor?
A Descriptor is an object that defines at least one of these methods:
-
__get__()→ for retrieving value -
__set__()→ for setting value -
__delete__()→ for deleting value
In simple terms: A descriptor controls how attributes behave.
Descriptor Protocol
A class becomes a descriptor if it implements:
__get__(self, instance, owner)
__set__(self, instance, value)
__delete__(self, instance)
Simple Descriptor Example
class Descriptor:
def __get__(self, instance, owner):
print("Getting value")
return instance._value
def __set__(self, instance, value):
print("Setting value")
instance._value = value
class MyClass:
attr = Descriptor()
def __init__(self, value):
self._value = value
obj = MyClass(10)
print(obj.attr)
obj.attr = 20
print(obj.attr)
Output:
Getting value
10
Setting value
Getting value
20
How Descriptors Work
When you access:
obj.attr
Python internally calls:
Descriptor.__get__(obj, MyClass)
When you assign:
obj.attr = 50
Python calls:
Descriptor.__set__(obj, 50)
Types of Descriptors
1. Data Descriptor
Implements both:
-
__get__ -
__set__
✔ Has priority over instance dictionary
2. Non-Data Descriptor
Implements only:
-
__get__
✔ Lower priority than instance attributes
Example: Data Descriptor (Validation)
class AgeValidator:
def __get__(self, instance, owner):
return instance._age
def __set__(self, instance, value):
if value < 0:
raise ValueError("Age cannot be negative")
instance._age = value
class Person:
age = AgeValidator()
def __init__(self, age):
self.age = age
p = Person(25)
print(p.age)
p.age = 30
print(p.age)
Example: Non-Data Descriptor
class NonData:
def __get__(self, instance, owner):
return "Descriptor value"
class MyClass:
attr = NonData()
obj = MyClass()
print(obj.attr)
Real-World Use Case: Property-like Behavior
Descriptors are the foundation of @property.
class Celsius:
def __init__(self, temperature=0):
self._temperature = temperature
def get_temp(self):
return self._temperature
def set_temp(self, value):
if value < -273.15:
raise ValueError("Invalid temperature")
self._temperature = value
temperature = property(get_temp, set_temp)
c = Celsius(25)
print(c.temperature)
c.temperature = 30
Descriptor vs Property
| Feature | Descriptor | Property |
|---|---|---|
| Flexibility | High | Medium |
| Complexity | Advanced | Simple |
| Usage | Frameworks | Everyday coding |
| Control | Full control | Limited |
Where Descriptors Are Used
Descriptors are used internally in:
- Functions (methods)
- Properties
- Class variables
- ORM frameworks (Django, SQLAlchemy)
- Validation systems
Why Use Descriptors?
- Encapsulation
- Data validation
- Reusable attribute logic
- Cleaner code structure
- Advanced OOP control
Advantages
- Powerful attribute control
- Reusable logic
- Used in core Python internals
- Enables advanced frameworks
Limitations
- Hard to understand for beginners
- More complex than properties
- Overkill for simple use cases
Summary
Descriptors in Python allow you to control attribute access using special methods like __get__, __set__, and __delete__.
They are a fundamental part of Python’s object model and are widely used in advanced systems built with Python.
Conclusion
If you want to master advanced object-oriented programming in Python, understanding descriptors is essential.
They give you full control over attribute behavior and are the backbone of many Python features like properties and frameworks.


0 Comments