`__init__` constructor — initializing attributes
WHY does __init__ exist?
WHAT exactly is __init__?
HOW does a call actually work? (Derivation from scratch)
Let's derive what obj = Person("Asha", 30) really does, step by step. Nothing is magic.
Step 1 — Calling the class triggers type.__call__.
Why? A class is itself an object (instance of type). Using () on it invokes type.__call__.
Step 2 — __call__ calls __new__ to allocate a blank object.
obj = Person.__new__(Person) # empty Person, no attributes yetWhy? You need a memory shell before you can fill it.
Step 3 — __call__ calls __init__ on that blank object.
Person.__init__(obj, "Asha", 30) # self=obj, name="Asha", age=30Why this step? This is where self.name = name actually runs, attaching data.
Step 4 — __call__ returns obj.
Why? So obj = Person(...) gets the finished object.
So the equivalence you can derive and verify:

Worked Examples
Common Mistakes (Steel-manned)
Forecast-then-Verify
Flashcards
When is __init__ called?
Cls(...)).Does __init__ create the object?
__new__ creates the blank object; __init__ only initializes its attributes.What is self?
What must __init__ return?
None (returning anything else raises TypeError).Difference between self.name = name and name = name in __init__?
__init__ ends).Why is def __init__(self, x=[]) dangerous?
x=None then assign [] inside.What does Cls(args) expand to?
o = Cls.__new__(Cls); Cls.__init__(o, args); return o.Why put validation inside __init__?
Recall Feynman: explain to a 12-year-old
Imagine buying a brand-new schoolbag. The shop first hands you an empty bag (that's __new__). Then, before giving it to you, they fill it with your name tag, books, and pencils so it's ready to use (that's __init__). self is just "this bag" — when they write "this bag's name = Asha," they mean your specific bag, not someone else's. Every bag goes through the same filling station, so no bag ever leaves empty or broken.
Connections
- OOP Fundamentals —
__init__is the foundation of object creation. - self and instance attributes — what
self.x = ...actually stores. - __new__ vs __init__ — allocation vs initialization.
- Class vs Instance Attributes —
__init__sets instance attributes. - Properties and computed attributes — alternative to computing in
__init__. - Mutable default argument pitfall — the shared-default trap.
- Dunder methods —
__init__is one of many special methods.
Concept Map
Hinglish (regional understanding)
Intuition Hinglish mein samjho
Dekho, jab tum p = Person("Asha", 30) likhte ho, toh do alag cheezein hoti hain. Pehle Python ek khaali object banata hai (ye __new__ ka kaam hai), aur phir turant __init__ naam ka special method chalata hai jo us khaali object ke andar data bharta hai. Isliye __init__ ko constructor ya setup method bolte hain — iska kaam object create karna nahi, balki uske attributes initialize karna hai.
self ka matlab hai "yehi object jo abhi ban raha hai". Jab tum self.name = name likhte ho, toh iska matlab hai "is object ke upar name naam ka attribute store kar do". Yahan left side self.name object ka hissa hai jo baad tak rahega, aur right side name sirf ek local parameter hai jo __init__ khatam hote hi gaayab ho jaata hai. Agar tum sirf name = name likh do bina self. ke, toh data kahin save nahi hota — ye sabse common galti hai.
Constructor important kyun hai? Kyunki ye ek single gateway hai jise har object ko paar karna padta hai. Yahan tum default values de sakte ho, validation laga sakte ho (jaise temperature -273.15 se neeche nahi), aur guarantee kar sakte ho ki koi bhi galat object kabhi bane hi na. Bas ek warning: default argument me kabhi mutable cheez ([] ya {}) mat do — woh saare objects me share ho jaati hai. Uski jagah None do aur andar [] bana lo.