Properties — `@property`, `@setter`, `@deleter` for controlled access
2.1.7· Coding › OOP Fundamentals
Properties kyun exist karti hain?
Attribute ko directly expose kyun nahi karte? Kyunki tab koi bhi rok nahi hai koi likhe
account.balance = -9999. Tum apne invariants kho dete ho (woh rules jo hamesha hold hone chahiye).
Sirf get_x()/set_x() methods kyun nahi use karte? Kyunki tab har call site ko likhna padta hai
obj.get_x(). Agar tumne obj.x se shuru kiya tha, toh switch karne se woh saara code toot jaata hai. Properties tumhe
clean obj.x syntax bhi rakhne deti hain aur control bhi milta hai.
Property mechanically KIYA hoti hai?
Decorators sirf sugar hain:
class C:
@property
def x(self): # this is property(x).fget
return self._x
@x.setter
def x(self, value): # returns a NEW property with fset filled in
self._x = value
@x.deleter
def x(self): # fills in fdel
del self._xPython obj.x ko kaise resolve karta hai (derivation)
Jab tum obj.x access karte ho, Python sirf obj.__dict__ mein nahi dekhta. Attribute
lookup descriptor protocol follow karta hai:
type(obj).__mro__mein naamxdhundho.- Agar mila AUR yeh ek data descriptor hai (defines
__set__ya__delete__) →x.__get__(obj, type(obj))call karo. Yeh instance__dict__se jeetta hai. - Warna
obj.__dict__['x']check karo. - Warna agar ek non-data descriptor (sirf
__get__) mila tha → use karo. - Warna
AttributeError.

Worked Example 1 — Validation (Temperature)
class Temperature:
def __init__(self, celsius):
self.celsius = celsius # goes THROUGH the setter ✔
@property
def celsius(self):
return self._celsius
@celsius.setter
def celsius(self, value):
if value < -273.15:
raise ValueError("below absolute zero")
self._celsius = value
@property
def fahrenheit(self): # computed, read-only
return self._celsius * 9/5 + 32| Step | Code | Yeh step kyun? |
|---|---|---|
| 1 | self.celsius = celsius in __init__ |
Construction ke time bhi property use karo, taaki validation birth se hi chale. |
| 2 | store in self._celsius |
Backing field ek alag naam (_celsius) use karta hai taaki setter khud ko hamesha ke liye call na kare. |
| 3 | fahrenheit ka koi setter nahi |
Read-only computed value — celsius se derive hoti hai, isliye ise directly set karna ambiguous hoga. |
t = Temperature(25)
t.fahrenheit # 77.0 (computed, no stored field)
t.celsius = -300 # ValueErrorWorked Example 2 — Read-only + deleter (Account)
class Account:
def __init__(self, balance):
self._balance = balance
@property
def balance(self):
return self._balance # no setter ⇒ can't reassign
@balance.deleter
def balance(self):
print("closing account")
self._balance = 0| Step | Code | Yeh step kyun? |
|---|---|---|
| 1 | koi @balance.setter define nahi |
acc.balance = 5 ko AttributeError raise karwa deta hai → balance sirf deposit/withdraw methods se change ho sakta hai. |
| 2 | @balance.deleter 0 par reset karta hai |
del acc.balance ek controlled "close" action ban jaata hai, memory wipe nahi. |
acc = Account(100)
acc.balance # 100
acc.balance = 50 # AttributeError: can't set attribute
del acc.balance # prints "closing account", balance -> 0Worked Example 3 — Lazy / cached computation
class Circle:
def __init__(self, r):
self._r = r
self._area = None
@property
def area(self):
if self._area is None: # compute once, then cache
print("computing...")
self._area = 3.141592653589793 * self._r ** 2
return self._area
@property
def radius(self):
return self._r
@radius.setter
def radius(self, v):
self._r = v
self._area = None # invalidate cache!Yeh step kyun? radius set karne par _area reset hona chahiye, warna area ek stale
cached value return karta hai. Properties tumhe derived data ko consistent rakhne ka hook deti hain.
Recall Feynman: ek 12-saal ke bachche ko samjhao
Socho ek vending machine hai jisme "Money" likha ek slot hai. Bahar se yeh ek simple
slot lagta hai — tum bas paisa daalo. Lekin andar, ek chota guard check karta hai: kya yeh asli sikka hai? kafi
paisa hai? Agar nahi, toh woh wapas de deta hai. Property wahi guard hai. Bahar se machine.money = 5
lagta hai jaise slot mein sikka daala, lekin ek hidden checker (setter) decide karta hai ki accept karna hai ya nahi.
Ek read-only property woh slot hai jisme tum sirf dekh sakte ho andar kya hai (@property) lekin
guard tumhe kuch push karne nahi deta (koi @setter nahi).
Flashcards
@property ek method ko kiya banata hai?
obj.x ko method run karwaata hai jabki plain attribute access jaisa lagta hai.Ek setter ke andar self.x ki jagah self._x mein data kyun store karte hain?
self.x assign karne se setter phir se trigger hota → infinite recursion; _x ek alag backing field hai.Kaunsi error raise hoti hai obj.x = v se jab sirf @property define ho (koi setter nahi)?
Property x mein setter add karne ka syntax kiya hai?
@x.setter ek method named x ke upar (same naam).Property ek instance __dict__ entry ko same naam se kyun override karti hai?
__set__), isliye descriptor lookup instance dict se jeett jaata hai.@x.deleter kiya control karta hai?
del obj.x par kiya hota hai — tumhe attribute ko blindly remove karne ki jagah cleanly cleanup karne deta hai.Kaunsa principle kehta hai ki callers ko yeh nahi pata hona chahiye ki obj.x stored hai ya computed?
Property ke saath cache karte waqt, source value ke setter ko kiya karna chahiye?
Kiya ek read-only property ki underlying value immutable hai?
_x change kar sakti hain.Ek property kaun se teen functions rakh sakti hai?
Connections
- Encapsulation and Access Modifiers — properties Python ke "hum sab adults hain" tarike se encapsulation enforce karti hain.
- Descriptors __get__ __set__ __delete__ — lower-level mechanism jis par
propertybana hai. - Getters and Setters in Java vs Python — same goal, cleaner syntax.
- functools.cached_property — built-in caching property.
- Class vs Instance Attributes — property class par rehti hai; backing field instance par.
- Invariants and Class Design — setters mein validation object state kyun protect karta hai.