2.1.3 · Coding › OOP Fundamentals
Intuition Ek sentence mein core baat
Ek class attribute har object ke saath shared hota hai (ek hi copy, class pe rehti hai), jabki ek instance attribute sirf ek object ka apna hota hai (uski khud ki copy, self pe rehti hai).
Intuition Yeh distinction kyun exist karti hai
Class ko ek cookie cutter aur objects ko cookies samjho.
Kuch facts cutter se banne wali saari cookies ke liye sach hote hain → unhe cutter pe ek baar store karo (class attribute). Example: "saare dogs species Canis familiaris ke hain".
Kuch facts har cookie ke liye alag hote hain → unhe har cookie pe store karo (instance attribute). Example: har dog ka apna name hota hai.
Shared data ko har instance pe rakhna memory waste karega aur updates painful ho jaayenge (1000 copies change karni padti). Per-object data ko class pe rakhna saare objects ko ek hi value pe collide karaega.
Class attribute : ek variable jo class body mein define hota hai (class X: ke directly neeche), kisi bhi method ke andar nahi. Class ke namespace mein stored hota hai (X.__dict__). Ek shared copy.
Instance attribute : ek variable jo ==self.name = value== ke zariye assign hota hai (usually __init__ mein). Us object ke namespace mein stored hota hai (obj.__dict__). Har object ki apni ek copy .
class Dog :
species = "Canis familiaris" # class attribute (shared)
def __init__ (self, name):
self .name = name # instance attribute (per object)
Intuition Lookup rule — har cheez isi se nikalti hai
Jab tum obj.x padhte ho, Python is order mein search karta hai:
instance obj.__dict__
phir class type(obj).__dict__
phir base classes (MRO)
Jab tum likhte ho obj.x = ..., Python hamesha instance pe attribute create/update karta hai — class ko kabhi modify nahi karta.
Yeh ek asymmetry (read = upar search karo, write = hamesha instance pe) neeche ki har tricky behaviour explain karti hai.
Worked example Class attribute ko read karna phir write karna
class Dog :
species = "Canis familiaris"
def __init__ (self, name): self .name = name
a = Dog( "Rex" )
b = Dog( "Fido" )
print (a.species) # 'Canis familiaris'
print (b.species) # 'Canis familiaris'
Yeh step kyun? Kisi bhi instance ke apne __dict__ mein species nahi hai, toh lookup class tak fall through karta hai → dono same shared value dekhte hain.
a.species = "Wolf" # WRITE → `a` pe ek instance attribute banata hai
print (a.species) # 'Wolf' (instance copy class ko shadow karti hai)
print (b.species) # 'Canis familiaris' (b abhi bhi class tak fall through karta hai)
print (Dog.species) # 'Canis familiaris' (class untouched!)
Yeh step kyun? a.species likhna write rule follow karta hai: usne a.__dict__ mein ek brand-new key banayi. Ab a ki read usse pehle (step 1) dhundh leti hai, toh class value shadow ho gayi, overwrite nahi. b aur Dog unaffected hain.
Dog.species = "Doggo" # class change karo → jo shadow nahi karte woh sab dekhte hain
print (a.species) # 'Wolf' (a shadows karta hai)
print (b.species) # 'Doggo' (b updated class tak fall through karta hai)
Yeh step kyun? Class pe editing karna single shared copy ko change karta hai; har wo instance jiske paas apna species nahi hai woh nayi value live dekhta hai.
Worked example Shared mutable list sabko kaatati hai
class Dog :
tricks = [] # class attribute — EK shared list
def __init__ (self, name): self .name = name
def add_trick (self, t): self .tricks.append(t) # KOI assignment nahi!
a, b = Dog( "Rex" ), Dog( "Fido" )
a.add_trick( "roll" )
print (b.tricks) # ['roll'] 😱 Fido ne Rex ki trick seekh li
Yeh kyun hota hai? self.tricks.append(...) ek read hai (shared class list dhundh leta hai) phir us object ko mutate karta hai . Koi self.tricks = ... assignment nahi hai, toh koi instance copy kabhi nahi banti. Dono dogs ek hi list share karte hain.
Fix — ise per-object instance attribute banao:
class Dog :
def __init__ (self, name):
self .name = name
self .tricks = [] # har instance ke liye fresh list (ek assignment!)
def add_trick (self, t): self .tricks.append(t)
Fix kyun kaam karta hai? Har __init__ self.tricks = [] run karta hai, ek assignment → har instance ke __dict__ mein alag list create hoti hai.
obj.x = 5 class attribute ko change karta hai"
Kyun sahi lagta hai: tum read karte ho obj.x aur ek second pehle class value mili, toh ise likhne se "wahi jagah" hit honi chahiye. Symmetry seductive lagti hai.
Fix: read aur write asymmetric hain. Write hamesha instance pe landing karti hai. Class value change karne ke liye, class pe likho: ClassName.x = 5.
Common mistake "Default ke liye class attribute use karo, phir bas mutate karo"
Kyun sahi lagta hai: "Yeh ek default list hai, sab empty start karte hain, toh ek shared empty list theek hai." DRY aur clean lagta hai.
Fix: mutation (.append, .update) state ko saare instances mein share karta hai. Class attributes sirf immutable / truly-shared data ke liye use karo; per-object mutable state __init__ mein self. ke zariye belong karta hai.
Common mistake "Class attributes static variables ki tarah hain jo change nahi ho sakte"
Kyun sahi lagta hai: doosri languages mein inhe static const kehte hain.
Fix: Python mein class attribute mutable aur ClassName.attr = ... ke zariye reassignable hai; "class" sirf woh kahan rehta hai batata hai, immutable nahi.
Recall Feynman: ek 12-saal ke bachche ko explain karo
Socho ek classroom hai. Saamne ek whiteboard hai jo sabke saath share hoti hai — agar teacher uspe "Homework: page 5" likhe, toh har student wahi message dekhta hai. Yahi class attribute hai.
Har student ke paas apni notebook bhi hai. Main apni notebook mein jo likhta hoon woh sirf mera hai; teri blank rehti hai. Yahi instance attribute hai.
Tricky part: agar main "homework change" karna chahoon, toh ya toh (a) apni notebook mein naya note likhoon (ab sirf main apna version dekhta hoon — whiteboard unchanged hai), ya (b) chalkboard tak jaake whiteboard rewrite karoon (sab ka homework change ho jaata hai). Python ka self.x = ... hamesha "apni notebook mein likho" hai; ClassName.x = ... hai "whiteboard rewrite karo".
"Self for self, Class for class."
self.x = ... → apni copy (WRITE = instance, hamesha ).
Sharing/change-for-all chahiye? Class name pe jao.
Aur: "Mutable default? Use __init__ mein move karo."
Class attribute aur instance attribute kahan stored hote hain?
obj.x = 5 kya karta hai agar x pehle sirf ek class attribute tha?
Do instances accidentally ek [] class attribute kyun share karte hain lekin ek int class attribute nahi jo per instance reassign hota hai?
Class attribute physically kahan stored hota hai? Class ke namespace mein (ClassName.__dict__); saare instances ke liye ek shared copy.
Instance attribute kahan stored hota hai? Us object ke apne namespace mein (obj.__dict__); har instance ki alag copy.
Python READ pe obj.x kaise resolve karta hai? Pehle instance __dict__, phir class, phir MRO ke zariye base classes.
obj.x = value hamesha kya karta hai, chahe x class attribute tha ya nahi?INSTANCE pe x create/update karta hai; class ko kabhi modify nahi karta.
"Shadowing" kya hai? Jab ek instance attribute same naam ke class attribute ko lookup mein hide karta hai, kyunki instance pehle search hota hai.
Mutable class attribute (jaise tricks = []) instances mein kyun share hota hai? Kyunki .append() single shared object ka read+mutate hai; bina assignment ke koi per-instance copy kabhi nahi banti.
Shared-mutable-default bug kaise fix karte hain? __init__ ke andar har instance ke liye fresh object assign karo (self.tricks = []).
Ek class attribute ko SAB instances ke liye ek saath kaise change karte hain? Class pe hi reassign karo: ClassName.attr = new_value.
a.species = "Wolf" ke baad, Dog.species kya return karega?Unchanged original class value — a ne sirf ek shadowing instance attribute add kiya.
Kya Python mein class attributes immutable hote hain? Nahi; "class" sirf batata hai woh kahan rehte hain, immutability nahi — inhe class name ke zariye reassign kiya ja sakta hai.
OOP Fundamentals
Classes and objects
The self parameter
__init__ constructor
Inheritance and MRO
Namespaces and scope
Mutable vs immutable objects