2.1.2OOP Fundamentals

`__init__` constructor — initializing attributes

1,786 words8 min readdifficulty · medium2 backlinks

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 yet

Why? 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=30

Why 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:

Figure — `__init__` constructor — initializing attributes

Worked Examples


Common Mistakes (Steel-manned)


Forecast-then-Verify


Flashcards

When is __init__ called?
Automatically, right after a new object is created (during Cls(...)).
Does __init__ create the object?
No — __new__ creates the blank object; __init__ only initializes its attributes.
What is self?
A reference to the specific instance being initialized; passed automatically as the first parameter.
What must __init__ return?
None (returning anything else raises TypeError).
Difference between self.name = name and name = name in __init__?
The first stores data on the object (persists); the second only reassigns a local variable (lost when __init__ ends).
Why is def __init__(self, x=[]) dangerous?
The default list is created once and shared across all instances; use 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__?
It's the single gateway all objects pass through, so it guarantees no invalid object exists.

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

invokes

first calls

then calls

finally returns

produces

passed as self

receives

assigns

must return

guarantees

rarely written

usually written

Cls args call

type dot __call__

__new__ allocates blank object

__init__ constructor

finished object

empty shell no attributes

self this object

instance attributes

None else TypeError

every object born valid

you write __init__

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.

Go deeper — visual, from zero

Test yourself — OOP Fundamentals

Connections