Database fields rely on Python’s Descriptor Protocol to manage data, and built-in properties like @property and staticmethod use it to control attribute access. Descriptors allow developers to define custom behavior for attributes, ensuring better control over how values are stored, retrieved, and modified.
What are Descriptors?
A descriptor is a Python object that controls attribute access through special methods:
__get__(self,instance,value) defines behavior when retrieving an attribute.
__set__(self,instance,value) Defines behavior when assigning a value.
__delete__(self,instance,value) Defines behavior when deleting an attribute.
By implementing these methods, we can customize how attributes work inside a class.
Why use descriptors?
- Encapsulation – Hide internal logic and enforce rules.
- Code Reusability – Create reusable attribute management logic.
- Validation – Ensure only valid data is stored.
Descriptors are used in ORMs, logging, caching, and computed properties, making Python more flexible.
Creation
Here’s and example of creating and using one:
class PositiveNumber: def __get__(self, instance, owner): return instance.__dict__.get(self.name, 0) def __set__(self, instance, value): if value < 0: raise ValueError("Value must be positive!") instance.__dict__[self.name] = value def __set_name__(self, owner, name): self.name = name class Product: price = PositiveNumber() #descriptor p = Product() p.price = 100 print(p.price) #100 p.price = -5 # ValueError value should be positive
PositiveNumber ensures that price only stores positive values, preventing invalid data entry.
@property
lets us define getter, setter, and deleter methods inside a class:
class Temperature: def __init__(self, celsius): self._celsius = celsius @property def celsius(self): return self._celsius @celsius.setter def celsius(self, value): if value < -273.15: raise ValueError("Temperature cant be below zero") self._celsius = value temp = Temperature(25) print(temp.celsius) # 25 temp.celsius = -300 # ValueError
When
- If there are multiple classes which need common attribute logic (ex: validation).
- When you need advanced control over attribute behavior.
- While using ORMs, caching, logging, or computed properties.
-
-
-
- ORMs let you interact with databases using objects instead of writing raw SQL, making data management easier.
- Caching stores frequently used data in memory so it doesn’t have to be reloaded every time, making programs run faster.
- Logging: Logging records events like errors, updates, or function calls in a program, helping with debugging and tracking activity.
- Computed Properties: These are attributes that calculate their value on the fly instead of storing it, saving memory and keeping data up to date.
-
-
-
Python’s Descriptor Protocol gives developers control over attribute access, making code cleaner, safer, and reusable. While @property works well for basic cases, descriptors allows more customization for complex applications.
So, next time you need custom attribute behavior, think beyond @property and try descriptors.