Python Descriptors Properties Slots & Data Binding
Introduction
Python is one of the most popular programming languages in Pakistan, widely used in web development, AI, data science, and automation. One of the most powerful but often misunderstood advanced features in Python is Python descriptors: properties, slots & data binding.
A descriptor is a special Python object that allows you to control how attributes are accessed, set, or deleted in a class. This is the foundation behind features like @property, method binding, and even frameworks like Django ORM.
For Pakistani students learning advanced Python, mastering descriptors is extremely valuable because:
- It improves understanding of how Python internally manages objects
- It helps you write cleaner and more secure code
- It is heavily used in real-world frameworks (Django, Flask extensions, data validation libraries)
In short, if you want to become an advanced Python developer in Lahore, Karachi, or Islamabad job markets, descriptors are a must-know concept.
Prerequisites
Before learning Python descriptors, you should already understand:
- Basic Python classes and objects
- Object-Oriented Programming (OOP) concepts
- Functions and decorators
- Basic understanding of
__init__method - Python dictionaries and attribute access
If you are not comfortable with these topics, first review:
- Python OOP fundamentals on theiqra.edu.pk
- Python functions and decorators tutorial
Core Concepts & Explanation
Descriptor Protocol (get, set, delete)
A descriptor is any object that implements at least one of these methods:
__get__(self, instance, owner)__set__(self, instance, value)__delete__(self, instance)
These methods control how attribute access works.
How it works:
When you access an attribute like:
obj.name
Python internally checks:
- Is
namea descriptor? - Does it have
__get__? - If yes, call
__get__instead of returning raw value
Simple Descriptor Example:
class UpperCaseString:
def __get__(self, instance, owner):
return instance._name
def __set__(self, instance, value):
instance._name = value.upper()
Line-by-line explanation:
class UpperCaseString:→ Defines a descriptor class__get__→ Runs when we access the attributeinstance._name→ Stores actual data inside object__set__→ Converts input to uppercase before savingvalue.upper()→ Ensures data consistency
Python property as Descriptor Shortcut
In Python, the @property decorator is just a built-in descriptor implementation.
class Student:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, value):
self._name = value.title()
Explanation:
@property→ Acts like__get__@name.setter→ Acts like__set___name→ private storage variable

This is why python property descriptor is considered a simplified version of full descriptors.
Practical Code Examples
Example 1: Data Validation Descriptor
Let’s create a descriptor that ensures age is always between 0 and 120.
class AgeValidator:
def __set_name__(self, owner, name):
self.name = name
def __get__(self, instance, owner):
return instance.__dict__.get(self.name)
def __set__(self, instance, value):
if not (0 <= value <= 120):
raise ValueError("Age must be between 0 and 120")
instance.__dict__[self.name] = value
class Person:
age = AgeValidator()
def __init__(self, name, age):
self.name = name
self.age = age
Line-by-line explanation:
class AgeValidator:→ Descriptor for validation__set_name__→ Automatically gets attribute name (age)instance.__dict__→ Stores actual values safelyif not (0 <= value <= 120)→ Validates age rangeraise ValueError→ Stops invalid dataPerson.age = AgeValidator()→ Attaches descriptor
Now usage:
p = Person("Ahmad", 25)
print(p.age)
If invalid:
p.age = 200 # Error
Example 2: Real-World Application (Bank Account System)
Imagine a banking system in Pakistan where users from Karachi, Lahore, and Islamabad manage accounts.
class BalanceDescriptor:
def __init__(self):
self.balance = {}
def __get__(self, instance, owner):
return self.balance.get(instance, 0)
def __set__(self, instance, value):
if value < 0:
raise ValueError("Balance cannot be negative")
self.balance[instance] = value
class BankAccount:
balance = BalanceDescriptor()
def __init__(self, owner, balance):
self.owner = owner
self.balance = balance
Explanation:
self.balance = {}→ Stores balances per objectinstance→ Each account object (Ahmad, Fatima, Ali)- Prevents negative balances
- Central control of attribute logic
Example usage:
acc1 = BankAccount("Ahmad", 5000)
acc2 = BankAccount("Fatima", 10000)
print(acc1.balance)

Common Mistakes & How to Avoid Them
Mistake 1: Overwriting Descriptor in Instance Dictionary
Problem:
class Demo:
value = AgeValidator()
obj = Demo()
obj.value = 50 # overwrites descriptor
Why it happens:
Instance dictionary takes priority over descriptor.
Fix:
Always store values inside instance.__dict__ or descriptor-managed storage.
Mistake 2: Confusing slots with Descriptors
Many students think __slots__ is a descriptor — it is not.
class Student:
__slots__ = ['name', 'age']
Explanation:
__slots__reduces memory usage- It does NOT manage attribute logic
- Descriptors control behavior, slots control storage

Practice Exercises
Exercise 1: Create a Marks Validator
Task:
Create a descriptor that only allows marks between 0 and 100.
Solution:
class Marks:
def __set_name__(self, owner, name):
self.name = name
def __get__(self, instance, owner):
return instance.__dict__.get(self.name)
def __set__(self, instance, value):
if not (0 <= value <= 100):
raise ValueError("Invalid marks")
instance.__dict__[self.name] = value
class Student:
marks = Marks()
Exercise 2: Temperature Converter Descriptor
Task:
Store temperature in Celsius but allow input in Fahrenheit.
Solution:
class Temperature:
def __get__(self, instance, owner):
return instance._celsius
def __set__(self, instance, value):
instance._celsius = (value - 32) * 5/9
class Weather:
temp = Temperature()
Frequently Asked Questions
What is a Python descriptor?
A descriptor is an object that defines how attribute access works using __get__, __set__, or __delete__. It allows controlled access to class attributes.
What is a python property descriptor?
A property descriptor is a simplified descriptor created using @property, which internally uses __get__ and __set__.
What is the use of get set in Python?
They are methods that control attribute reading and writing. __get__ is called when accessing an attribute, and __set__ is called when assigning a value.
How do descriptors relate to data binding?
Descriptors enable data binding by automatically updating or validating values whenever attributes change in an object.
Why are descriptors important in Python?
They are used in frameworks like Django, ORM systems, and validation libraries. They help build reusable and controlled attribute behavior.
Summary & Key Takeaways
- Descriptors control attribute access in Python using
__get__,__set__, and__delete__ @propertyis a built-in descriptor shortcut- They are widely used in real-world frameworks
__slots__reduces memory usage but is not a descriptor- Descriptors help implement validation, data binding, and computed attributes
- They improve code reusability and maintainability
Next Steps & Related Tutorials
To strengthen your Python skills further, explore:
- Learn more about Python OOP concepts on theiqra.edu.pk
- Master advanced Python with Python Metaclasses tutorial
- Understand decorators in depth with Python Decorators Guide
- Explore Django model fields and validation internals
Mastering descriptors will put you on a professional Python developer path, especially for backend and AI development roles in Pakistan’s growing tech industry.
Test Your Python Knowledge!
Finished reading? Take a quick quiz to see how much you've learned from this tutorial.