Python Advance Course
Descriptors in Python (Magic Methods Behind the Scenes)
Descriptors in Python (__get__, __set__, __delete__)
Descriptors are advanced Python objects that control attribute access in Python.
They are widely used in: - Django ORM fields - Pydantic validation - Flask internals - @property system
What is a Descriptor?
A descriptor is any object that defines at least one of:
- __get__
- __set__
- __delete__
1. __get__ (Attribute Access)
Used when you access:
obj.value
Example:
class Descriptor:
def __get__(self, instance, owner):
return "Hello from descriptor"
class MyClass:
value = Descriptor()
obj = MyClass()
print(obj.value)
Output:
Hello from descriptor
Graph
obj.value
↓
__get__ is called
↓
value returned
Real World Example (Logging Access)
class LogAccess:
def __get__(self, instance, owner):
print("Accessing attribute")
return instance._name
class User:
name = LogAccess()
def __init__(self, name):
self._name = name
u = User("Aman")
print(u.name)
2. __set__ (Attribute Assignment)
Used when:
obj.value = something
Example:
class Validator:
def __set__(self, instance, value):
if value < 18:
raise ValueError("Age must be >= 18")
instance._age = value
class Person:
age = Validator()
p = Person()
p.age = 20
print(p._age)
Graph
p.age = 20
↓
__set__ triggered
↓
validation runs
↓
value stored
Real World Example
Used in: - Django model fields - API validation - Forms
3. __delete__ (Attribute Deletion)
Used when:
del obj.value
Example:
class SafeDelete:
def __delete__(self, instance):
print("Deleting value")
del instance._name
class User:
name = SafeDelete()
def __init__(self, name):
self._name = name
u = User("Aman")
del u.name
Graph
del obj.name
↓
__delete__ runs
↓
cleanup executed
4. Full Descriptor (All Methods)
class NameDescriptor:
def __get__(self, instance, owner):
return instance._name
def __set__(self, instance, value):
if not value:
raise ValueError("Name cannot be empty")
instance._name = value
def __delete__(self, instance):
print("Name deleted")
del instance._name
class User:
name = NameDescriptor()
def __init__(self, name):
self.name = name
u = User("Aman")
print(u.name)
u.name = "Ravi"
del u.name
Descriptor Flow
Attribute Access
↓
Python checks descriptor
↓
__get__ / __set__ / __delete__
↓
Custom logic executes
5. Real World Mapping
| Action | Meaning |
|---|---|
| __get__ | read DB field |
| __set__ | validate input |
| __delete__ | cleanup/security |
6. Descriptor vs @property
| Feature | Descriptor | @property |
|---|---|---|
| Reusability | High | Low |
| Power | Very High | Medium |
| Framework usage | Heavy | Light |
7. How @property works internally
@property is actually a descriptor.
Flow: @property → __get__ internally → controlled attribute access
8. Common Mistakes
Mistake 1: Missing parameters
def __get__(self):
Correct:
def __get__(self, instance, owner):
Mistake 2: Wrong storage
self.age = value ❌
Correct:
self._age = value ✔
Mistake 3: Using descriptor on instance
obj = Descriptor()
Correct:
class A:
value = Descriptor()
Homework 1
Create Age Descriptor: - age must be >= 18
class Age:
def __get__(self, instance, owner):
return instance._age
def __set__(self, instance, value):
if value < 18:
raise ValueError("Too young")
instance._age = value
class Person:
age = Age()
def __init__(self, age):
self.age = age
p = Person(20)
print(p.age)
Homework 2
Logging descriptor:
class Logger:
def __get__(self, instance, owner):
print("Accessed")
return instance._value
def __set__(self, instance, value):
print("Updated")
instance._value = value
class Data:
value = Logger()
d = Data()
d.value = 100
print(d.value)
9. Real World Use Cases
| System | Usage |
|---|---|
| Django ORM | Field validation |
| Flask | Request handling |
| Pydantic | Data validation |
| Python internals | property system |
10. Visual Summary
Object attribute access ↓ Descriptor protocol triggered ↓ Custom logic executes ↓ Final value returned
Next Advanced Topics
- Metaclasses (VERY important next step)
- Django ORM internals
- __getattribute__ deep behavior
- Pydantic validation system
- Property vs Descriptor advanced patterns