Instance methods, class methods (`@classmethod`), static methods (`@staticmethod`)
WHY do we even need three kinds?
WHAT each one is
HOW the binding actually works (derivation from scratch)
We will derive why self "appears automatically", instead of memorising it.
So all three are the same mechanism with different "what do I inject" rules.

Worked Example 1 — A Circle showing all three
class Circle:
PI = 3.14159 # class attribute (shared)
def __init__(self, r):
self.r = r # instance attribute (per-object)
def area(self): # INSTANCE method
return Circle.PI * self.r ** 2 # needs self.r
@classmethod
def unit(cls): # CLASS method (factory)
return cls(1) # builds an instance via cls
@staticmethod
def is_valid(r): # STATIC method (pure helper)
return r > 0c = Circle(2)
c.area() # 12.566 -> needs the object's r
Circle.unit() # Circle(r=1) -> no object needed, uses cls
Circle.is_valid(-1) # False -> no self, no cls- Why
areais an instance method? It depends onself.r, which differs per object. - Why
unitis a classmethod (not static)? It returnscls(1). Usingclsmeans a subclassclass Ball(Circle)would getBall.unit()→ aBall, not aCircle. This is the killer reason to prefer@classmethodfor factories. - Why
is_validis static? It uses neither object data nor class data — it's just related logic.
Worked Example 2 — Why cls beats hard-coding the class name
class Animal:
species = "generic"
@classmethod
def describe(cls):
return f"I am a {cls.species}" # cls, NOT Animal
class Dog(Animal):
species = "dog"
Animal.describe() # "I am a generic"
Dog.describe() # "I am a dog" <-- cls is Dog here- Why this step (
cls.species)? Becauseclsis whatever class the call came through. Calling viaDogmakescls = Dog, so it correctly readsDog.species. Had we writtenAnimal.species, subclasses would be ignored.
Worked Example 3 — Alternate-constructor pattern (the 80/20 use of classmethods)
class Date:
def __init__(self, y, m, d):
self.y, self.m, self.d = y, m, d
@classmethod
def from_string(cls, s): # "2024-05-01"
y, m, d = map(int, s.split("-"))
return cls(y, m, d) # Why cls? subclass-friendly factory- Why this step? A class can have only one
__init__, but many ways to build an object. Classmethods give you multiple named constructors.
Common Mistakes (Steel-manned)
Recall Feynman: explain to a 12-year-old
Imagine a cookie cutter (the class) and the cookies it makes (the instances).
- An instance method asks about one specific cookie: "how big are YOU?" — it needs that cookie (
self). - A class method asks about the cutter itself: "make me a brand-new standard cookie" — it needs the cutter (
cls), not a cookie. - A static method is a sticky note taped to the cutter: a handy rule like "dough should be thicker than 0 cm" — it doesn't need the cutter or any cookie, it's just kept nearby because it belongs to the topic.
Flashcards
What automatic first argument does an instance method receive?
self, the specific instance the method was called on.What automatic first argument does a @classmethod receive?
cls, a reference to the class it was called through.What automatic argument does a @staticmethod receive?
Why prefer @classmethod over @staticmethod for factory/alternate constructors?
cls respects inheritance: a subclass call builds a subclass instance, not the parent.Rewrite c.area() as the equivalent explicit function call.
Circle.area(c) — the object becomes the first positional argument.Why must you write def f(self): and not def f(): for an instance method?
What does obj.method evaluate to under the hood?
type(obj).__dict__['method'].__get__(obj, type(obj)) — a bound method via the descriptor protocol.In a classmethod, why use cls.x instead of ClassName.x?
x use their own value; cls is the actual calling class.What happens when you assign self.PI = 3.14 if PI is a class attribute?
Which method type can read/modify both instance AND class state?
self, and the class is reachable via type(self)).Connections
- OOP Fundamentals - Classes and Objects
- Instance vs Class attributes
- Inheritance and method resolution order (MRO)
- Descriptors and the __get__ protocol
- Decorators
- Factory design pattern
Concept Map
Hinglish (regional understanding)
Intuition Hinglish mein samjho
Dekho, ek class ke andar jo functions hote hain unhe methods kehte hain. In teeno methods me actual difference sirf ek hai: pehla argument automatically kya pass hota hai. Instance method me self jaata hai — yaani jis particular object pe call kiya, wahi object. Class method (@classmethod) me cls jaata hai — yaani poori class khud, koi specific object nahi. Static method (@staticmethod) me kuch bhi automatic nahi jaata — ye bas ek normal helper function hai jo logically class ke saath rehta hai.
Andar ki kahani: jab tum c.area() likhte ho, Python uske peeche Circle.area(c) chala raha hota hai — object ko khud first argument bana ke bhej deta hai (descriptor protocol ki wajah se). Isiliye self likhna zaroori hai, warna "takes 0 arguments but 1 given" error aata hai. Yeh implicit nahi hai jaise Java/C++ me this.
Sabse important practical baat: jab tumhe alternate constructor ya factory banana ho (jaise Date.from_string("2024-05-01")), toh @classmethod use karo aur andar cls(...) se object banao. Kyun? Kyunki agar koi subclass banegi, toh cls automatically wahi subclass ban jaayegi, aur sahi type ka object milega. Agar tum @staticmethod me class ka naam hardcode kar doge, toh inheritance toot jaayegi.
Yaad rakhne ka simple rule: self = yeh object, cls = yeh class, static = kuch nahi. Jab decide karna ho — agar object ka data (self.r) chahiye toh instance, agar class ka data ya naya object banana hai toh classmethod, agar dono nahi chahiye toh static. Bas itna 80/20 yaad rakh lo, kaafi hai.