Closures
Closure tab banta hai jab ek inner function apne outer (enclosing) function ki variables ko "remember" karta hai, chahe outer function ka execution khatam ho chuka ho. Ye decorators ka bhi foundation hai (jo humne pehle dekha).
Closures useful hain jab tumhe "function factories" chahiye — functions jo customized versions of themselves return karte hain, based on kuch initial configuration.
def make_multiplier(factor):
def multiplier(x):
return x * factor # 'factor' outer function se "remembered" hai
return multiplier
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(5)) # 10 — factor=2 yaad hai
print(triple(5)) # 15 — factor=3 yaad hai (alag closure!)
# make_multiplier already khatam ho chuka hai, phir bhi 'factor' zinda hai
# har closure ka apna independent 'factor' hai- Closure = inner function jo outer ki variables remember karta hai
- Outer function khatam hone ke baad bhi variable zinda rehta hai
- Function factories aur decorators ka foundation
Closure ke andar se outer variable ko sirf READ kar sakte ho by default — modify karne ke liye nonlocal keyword zaroori hai (global keyword jaisa hi concept, lekin enclosing function scope ke liye, module-level ke liye nahi).
def make_counter():
count = 0
def increment():
nonlocal count # bina iske, count += 1 error dega
count += 1
return count
return increment
counter = make_counter()
print(counter()) # 1
print(counter()) # 2
print(counter()) # 3 — state persist hoti hai calls ke beechSimple state (ek-do variables) ke liye closures concise hain. Complex state (multiple related variables + methods) ke liye classes zyada readable/maintainable hain — "counter with just increment" closure ke liye theek hai, "BankAccount with balance, history, methods" class ke liye better hai.
# Closure — simple case:
def make_counter():
count = 0
def increment():
nonlocal count
count += 1
return count
return increment
# Class — complex case, better fit:
class Counter:
def __init__(self):
self.count = 0
def increment(self):
self.count += 1
return self.count
def reset(self):
self.count = 0