1.2.30 · D4 · HinglishIntroduction to Programming (Python)

ExercisesVariable scope — LEGB rule (Local, Enclosing, Global, Built-in)

2,753 words13 min read↑ Read in English

1.2.30 · D4 · Coding › Introduction to Programming (Python) › Variable scope — LEGB rule (Local, Enclosing, Global, Built-

Shuru karne se pehle, poore game ki ek picture — taaki baad ke har trace mein ek map ho jis par point kar sakein.

Figure — Variable scope — LEGB rule (Local, Enclosing, Global, Built-in)

Level 1 — Recognition

(Kya aap dekh kar naam le sakte ho?)

Exercise 1.1

Neeche diye code mein, har naam (total, add, print, n) ko us scope ke saath label karo jismein Python use dhundta hai.

total = 10                # line A
def add(n):               # line B
    print(total + n)      # line C
add(5)
Recall Solution 1.1
  • total line C par: add ke andar assign nahi hua, toh yeh Local nahi hai. Search jaari → Global (top level par assign hua, line A). Scope = G.
  • n line C par: yeh add ka parameter hai. Parameters function call hone par assign hote hain, toh n Local hai. Scope = L.
  • print line C par: L nahi, E nahi (koi enclosing function nahi), G nahi → Built-in mein milta hai. Scope = B.
  • add line B par: top level par (def ke zariye) assign hua → Global.

Output: add(5) print karta hai total + n = 10 + 5 = 15.

Exercise 1.2

Inme se kaun sa Python mein ek naya scope banata hai? for loop · function body · if block · module (file) · list comprehension.

Recall Solution 1.2

Naya scope: function body, module, list comprehension. Nahi banate naya scope: for loop, if block. for/if ke andar assign hue naam surrounding function/module mein rehte hain — woh bahar leak ho jaate hain.


Level 2 — Application

(READ order apply karo aur output predict karo.)

Exercise 2.1

x = "G"
def outer():
    x = "E"
    def inner():
        x = "L"
        return x
    return inner()
print(outer())

Kya print hoga, aur kaun sa room jeet gaya?

Recall Solution 2.1

inner ke andar, x assign hota hai (x = "L"), toh x inner ke liye Local hai. return x mein x read karte waqt L pehle milta hai → "L". Output: L.

Exercise 2.2

Exercise 2.1 se line x = "L" hata do taaki inner ban jaaye:

def inner():
    return x

Ab kya print hoga?

Recall Solution 2.2

inner ab x assign nahi karta, toh x Local nahi hai. Search order: L (miss) → E = outer ke locals, jisme x = "E" hai → hit. Output: E. Python kabhi G tak nahi pahunchta.

Exercise 2.3

len = 5
print(len("hi"))

Result predict karo.

Recall Solution 2.3

Module level par len = 5 ek Global naam len banata hai. Jab len("hi") len ko read karta hai, LEGB check karta hai L (miss) → E (koi nahi) → G (len = 5, mila!) → Built-in se pehle ruk jaata hai. Toh len integer 5 hai, aur 5("hi") ek integer ko call karne ki koshish karta hai → TypeError: 'int' object is not callable. Yahi built-in ko shadowing karna hai.


Level 3 — Analysis

(Diagnose karo ki code error kyun de raha hai, WRITE rule use karke.)

Exercise 3.1

count = 0
def bump():
    count = count + 1
    return count
bump()

Yeh error raise karta hai. Iska naam lo aur exact line aur reason explain karo.

Recall Solution 3.1

Error: UnboundLocalError: local variable 'count' referenced before assignment, line count = count + 1 par. Reason: count bump ke andar = ke left side par aata hai, toh WRITE rule se count poore function ke liye Local hai. Right side count + 1 evaluate karne ke liye local count read karna padega — lekin abhi tak assign nahi hua. Python global count par fall back nahi karta; WRITE rule pehle hi decide kar chuka tha ki count Local hai.

Exercise 3.2

def outer():
    def inner():
        nonlocal y
        y = 1
    inner()
outer()

Kya yeh run hoga? Agar nahi, toh kyun?

Recall Solution 3.2

Yeh compile/def time par error deta hai: SyntaxError: no binding for nonlocal 'y' found. Reason: nonlocal y demand karta hai ki y pehle se kisi enclosing function mein exist kare (E). Lekin outer kabhi y assign nahi karta. Koi enclosing y nahi hai jisse bind kiya jaaye, toh nonlocal statement illegal hai. Fix: outer ke andar (inner se pehle) y = 0 add karo, nonlocal y ko target dene ke liye.

Exercise 3.3

x = 10
def f():
    print(x)
    x = 20
f()

Dhyan se trace karo. print(x) line par kya hota hai?

Recall Solution 3.3

Kyunki f mein baad mein x = 20 aata hai, WRITE rule x ko poore function ke liye Local mark kar deta hai — pehle wale print(x) ko bhi include karte hue. Toh print(x) local x padhne ki koshish karta hai assign hone se pehleUnboundLocalError. Trap yeh hai: assignment print ke neeche hai, phir bhi upar wale print ko kharaab kar deta hai. Scope ek saath poore function body ke liye decide hota hai, line by line nahi.


Level 4 — Synthesis

(Working code banane ke liye global, nonlocal, aur closures combine karo.)

Exercise 4.1

Exercise 3.1 ko fix karo taaki bump() module-level count ko sach mein increment kare. Phir use 3 baar call karo aur final count batao.

Recall Solution 4.1
count = 0
def bump():
    global count
    count = count + 1
    return count
bump(); bump(); bump()
print(count)   # 3

global count Python ko bolta hai "Local-creation rule skip karo; count yahan module-level naam ka matlab hai." Har call global ko read karke rebind karta hai. 3 calls ke baad, count == 3.

Exercise 4.2

Ek counter closure banao: ek function make_counter() jo ek function return kare jo, har baar call hone par, 1, 2, 3, … return kare. nonlocal use karo.

Recall Solution 4.2
def make_counter():
    n = 0                 # lives in Enclosing scope
    def step():
        nonlocal n        # bind to outer n, not a new local
        n += 1
        return n
    return step
 
c = make_counter()
print(c(), c(), c())      # 1 2 3

n make_counter ke scope (E) mein rehta hai. step ke andar, n += 1 ek write hai, toh nonlocal ke bina yeh ek fresh local banata aur error deta (n referenced before assignment). nonlocal n ise enclosing n ki taraf point karta hai, jo calls ke beech survive karta hai kyunki returned step us enclosing scope ko alive rakhta hai — yahi ek closure hai.

Exercise 4.3

Same factory se do independent counters:

a = make_counter()
b = make_counter()
print(a(), a(), b(), a())   # ?
Recall Solution 4.3

Output: 1 2 1 3. Har make_counter() call apna khud ka enclosing scope banata hai apne n ke saath. a aur b n share nahi karte. Toh a 1,2,…,3 count karta hai jabki b independently 1 se shuru hota hai.


Level 5 — Mastery

(Full-trace problems jahan kaafi saari rules interact karti hain — exact output predict karo.)

Exercise 5.1

x = "G"
def outer():
    x = "E"
    def inner():
        global x
        x = "changed"
    inner()
    return x
r = outer()
print(r, x)

Do printed values predict karo.

Recall Solution 5.1

inner ke andar, global x module ke x ko target karta hai, outer ke x ko NAHI. Toh x = "changed" global ko rebind karta hai. outer ka local x ("E") untouched rehta hai.

  • outer ke andar return x outer ka local x = "E" read karta hai, toh r == "E".
  • Global x ab "changed" hai. Output: E changed.

Exercise 5.2

def f():
    total = 0
    for i in range(3):
        total += i
    return total, i
print(f())

Kya loop ke baad i exist karta hai? Output kya hai?

Recall Solution 5.2

for loop scope nahi banata. i f ke body mein assign hota hai, toh i f ke liye Local hai aur loop ke baad survive karta hai. Iska last value 2 hai (range(3) → 0,1,2). total = 0+0+1+2 = 3. Output: (3, 2).

Exercise 5.3

Comprehension scope ki subtlety:

x = "G"
squares = [x for x in range(3)]
print(x)

Kya print hoga, aur yeh upar wale for loop se alag kyun hai?

Recall Solution 5.3

Ek list comprehension ka apna scope hota hai (for statement ke unlike). Comprehension ka x ek alag Local hai jo bahar leak nahi hota. Toh module-level x kabhi touch nahi hota. Output: G. 5.2 se compare karo: ek plain for i ko leak karta hai; ek comprehension ka loop variable leak nahi hota. Same dikhne wale loops, alag scope rules.

Exercise 5.4

Grand finale — sab combine karo:

val = "global"
def a():
    val = "enclosing"
    def b():
        def c():
            return val
        return c()
    return b()
print(a())

c val kaunse room se read karta hai?

Recall Solution 5.4

c val assign nahi karta, toh woh bahar dhundta hai: L (miss) → E. c ki enclosing chain hai b, phir a. b mein koi val nahi hai; a mein val = "enclosing" hai. Woh pehla E-room hai jisme naam hai → hit. Output: enclosing. Python Global se pehle ruk jaata hai.


Active Recall

The WRITE rule marks a naam Local when
naam = ke left par aata hai, += mein, for target ke roop mein, def, ya import mein — function mein kahin bhi, jab tak global/nonlocal use na kiya ho.
Kisi naam ko read karne par rooms is order mein search hote hain
Local → Enclosing → Global → Built-in (first hit wins).
Ek function mein x = 20 ke pehle print(x) raise karta hai
UnboundLocalError, kyunki baad wala assignment x ko poore function ke liye Local bana deta hai.
nonlocal y jab koi enclosing y na ho toh deta hai
ek SyntaxError (no binding for nonlocal found).
Ek plain for i in range(3) loop ke baad i equal hota hai
2 ko — loop scope nahi banata, toh i leak hota hai aur apni last value rakhta hai.
Ek list comprehension ka loop variable
apna scope rakhta hai aur surrounding function/module mein leak NAHI hota.
Kisi nested function ke andar global x target karta hai
module-level x (G) ko, saare enclosing functions ko skip karke.
make_counter() factory ke do calls apna n share karte hain?
Nahi — har call ka apna alag enclosing scope hota hai, toh counters independent hain.

Connections

  • Functions and Parameters — har exercise ka scope ek function call se banata hai; parameters Local names hain.
  • NameError and UnboundLocalError — Levels 3 aur 5 inn dono errors ki pure diagnosis hain.
  • Closures and Nested Functions — Exercises 4.2–4.3 aur 5.4 Enclosing scope par closures hain.
  • Namespaces and the dict model — har "room" parde ke peeche ek namespace dict hai.
  • Mutable vs Immutable arguments — ek companion trap: rebinding vs mutating.
  • Modules and import — Global room woh module namespace hai jo import se populate hota hai.