1.2.31 · D4 · HinglishIntroduction to Programming (Python)

Exercisesglobal and nonlocal keywords

2,441 words11 min read↑ Read in English

1.2.31 · D4 · Coding › Introduction to Programming (Python) › global and nonlocal keywords

Figure — global and nonlocal keywords

Shuru karne se pehle, woh do rules dobara yaad karo jo sab kuch decide karte hain:

Har ek ko pehle paper par karo, PHIR solution kholo. Yahi self-test page ka poora point hai.


Level 1 — Recognition

(Kya tum spot kar sakte ho ki kaunsa naam kaunse scope mein rehta hai, aur keyword ki zaroorat bhi hai ya nahi?)

L1.1

Har line ke liye batao ki global/nonlocal needed hai ya not needed, aur kyun.

total = 0
def a(): print(total)          # (i)
def b(): total = 5             # (ii)  -- want to change the module total
def c(): mylist.append(3)      # (iii) -- mylist is a module list
def d(): total = total + 1     # (iv)  -- want to change module total
Recall Solution L1.1
  • (i) not needed. Hum sirf total read kar rahe hain. Rule R ladder climb karta hai: koi local total nahi mila, toh global mil jaata hai. Reading ke liye kabhi keyword ki zaroorat nahi.
  • (ii) needed → global total. Hum total assign kar rahe hain. Rule A se ek bilkul naya local total = 5 ban jaata hai aur module wala chhoota rehta hai. Module variable change karne ke liye global total declare karna padega.
  • (iii) not needed. mylist.append(3) ek mutation hai object ki, naam mylist ki rebinding nahi. Koi mylist = ... nahi hai, isliye Rule A kabhi fire nahi hota. Dekho Mutable vs Immutable objects.
  • (iv) needed → global total. (ii) se bhi zyada bura: yahan right-hand side total read karta hai, lekin Rule A ne usse already local mark kar diya hai, toh read ko local-with-no-value milta hai → UnboundLocalError. global total dono sides ko fix karta hai.

L1.2

Har reference ke liye scope level batao (L, E, G, ya B):

len_ = len            # (i)  len
name = "top"
def outer():
    name = "mid"
    def inner():
        print(name)   # (ii) name
        print(len)    # (iii) len
    inner()
Recall Solution L1.2
  • (i) B (Built-in). len locally, kisi enclosing func mein, ya module level par define nahi hai → yeh Built-in scope se aata hai. (Yeh LEGB ki aakhiri rung hai.)
  • (ii) E (Enclosing). inner ke paas koi local name nahi; nearest enclosing function outer ke paas name = "mid" hai, toh yeh mid print karta hai. Yeh wahan rok leta hai — yeh module waale "top" tak chadhta nahi.
  • (iii) B (Built-in). Koi local, enclosing, ya global len nahi, toh phir se Built-in.

Level 2 — Application

(Printed output predict karo.)

L2.1

x = 10
def f():
    global x
    x = x + 5
f()
f()
print(x)
Recall Solution L2.1 — prints

20 global x Rule A ko cancel karta hai: x f mein har jagah module variable hai. Start x = 10. Pehla call: 10 + 5 = 15. Doosra call: 15 + 5 = 20. Print 20.

L2.2

def make_adder(step):
    total = 0
    def add():
        nonlocal total
        total += step
        return total
    return add
 
g = make_adder(3)
print(g(), g(), g())
Recall Solution L2.2 — prints

3 6 9 add ek closure hai make_adder ke locals total aur step par. nonlocal total add ki assignment ko enclosing total ("next-door box") ki taraf point karta hai, jo calls ke beech survive karta hai. step = 3. Calls: 0+3=3, 3+3=6, 6+3=9 → prints 3 6 9.

L2.3

count = 100
def outer():
    count = 1
    def inner():
        global count
        count = count + 1
    inner()
    return count
print(outer(), count)
Recall Solution L2.3 — prints

1 101 Dhyaan se trace karo — yeh classic global-vs-nonlocal confusion hai:

  • inner global count kehta hai, toh yeh module count (100) edit karta hai, outer ka local count (1) nahi. Module 101 ho jaata hai.
  • outer apna KHUD ka local count return karta hai, jo kabhi touch nahi hua → 1.
  • Toh outer()1, aur module count101. Prints 1 101.

Level 3 — Analysis

(Bug dhoondo aur exact mechanism explain karo.)

L3.1

Yeh 1 print karna chahiye, lekin crash hota hai. Kaun sa error aur kyun?

n = 0
def tick():
    n += 1
    print(n)
tick()
Recall Solution L3.1 —

UnboundLocalError n += 1 matlab n = n + 1 hai, ek assignment. Rule A n ko tick ke liye poori tarah local stamp karta hai. Right-hand side phir local n read karta hai, jiske paas abhi koi value nahi → UnboundLocalError: local variable 'n' referenced before assignment. Dekho UnboundLocalError. Fix: tick ki pehli line mein global n add karo, taaki n dono sides par module variable refer kare.

L3.2

Yeh SyntaxError raise karta hai. nonlocal ko kuch kyun nahi milta?

def f():
    def g():
        nonlocal k
        k = 5
    g()
f()
Recall Solution L3.2 —

SyntaxError: no binding for nonlocal 'k' found nonlocal ke liye ek already-existing variable chahiye enclosing function scope mein bind karne ke liye. f mein koi k define nahi hai, toh g ka nonlocal k point karne ke liye koi enclosing k nahi hai. global ke unlike (jo module-level naam create kar deta hai), nonlocal compile time par hi mana kar deta hai. Fix: g se pehle f ke andar k = 0 define karo.

L3.3

append kyun kaam karta hai lekin = fail karta hai?

data = []
def add_ok():
    data.append(1)     # works
def add_bad():
    data = data + [1]  # crashes
Recall Solution L3.3
  • add_ok: data.append(1) kabhi data = ... nahi likhta. Yeh sirf us list object ko mutate karta hai jis par naam already point karta hai. Koi assignment nahi ⇒ Rule A kabhi fire nahi hota ⇒ data global wala rehta hai ⇒ works.
  • add_bad: data = data + [1] naam data ko rebind karta hai. Rule A data ko local banata hai; right-hand side not-yet-assigned local read karta hai → UnboundLocalError. Fix: global data, ya behtar, mutate karo: data.append(1). Dekho Mutable vs Immutable objects.

Level 4 — Synthesis

(Spec match karne ke liye code design ya repair karo.)

L4.1

Ek bank() factory banao jo do functions return kare deposit(amount) aur balance(). deposit running balance mein add kare; balance() usse return kare. Koi global variables allowed nahi.

Recall Solution L4.1
def bank():
    money = 0
    def deposit(amount):
        nonlocal money      # rebinding the enclosing 'money'
        money += amount
    def balance():
        return money        # only reading -> no keyword needed
    return deposit, balance
 
d, b = bank()
d(100); d(50)
print(b())   # 150

money bank mein rehta hai. deposit usse rebind karta hai → nonlocal chahiye. balance sirf usse read karta hai → kuch nahi chahiye (Rule R enclosing scope tak chadh jaata hai). Dono closures ek hi money box share karte hain, toh deposits balance ko visible hote hain. Result: 150.

L4.2

Isko repair karo taaki yeh pehle enclosing_changed phir global_original print kare.

x = "global_original"
def outer():
    x = "enclosing_original"
    def inner():
        global x               # (bug is here)
        x = "enclosing_changed"
    inner()
    print(x)
outer()
print(x)
Recall Solution L4.2

Jaise likha hai, global x inner ko module x edit karwata hai → module "enclosing_changed" ho jaata hai, lekin outer ka local x chhoota rehta hai, toh woh "enclosing_original" phir "enclosing_changed" print karta hai — spec ka ulta. Fix: global x ko nonlocal x se badlo:

def inner():
    nonlocal x
    x = "enclosing_changed"

Ab inner outer ka x rebind karta hai → outer "enclosing_changed" print karta hai; module x kabhi touch nahi hota → "global_original" print hota hai. ✓


Level 5 — Mastery

(Multiple interacting scopes ke saath full traces.)

L5.1

Charon printed lines predict karo.

v = "G"
def outer():
    v = "E"
    def mid():
        nonlocal v
        v = "E2"
        def inner():
            global v
            v = "G2"
        inner()
        print(v)      # (1)
    mid()
    print(v)          # (2)
outer()
print(v)              # (3)
Recall Solution L5.1 — prints

E2, E2, G2 Do alag boxes track karo: module v aur outer's v.

  1. mid: nonlocal vouter ke v se bind; usse "E2" set karta hai.
  2. inner: global vmodule v se bind; usse "G2" set karta hai. Yeh outer ke v ko touch nahi karta.
  3. (1) par print(v) mid ke andar hai, jiska v = outer ka v = "E2".
  4. (2) par print(v) outer ke andar hai, uska v = "E2".
  5. (3) par print(v) module level par hai = "G2". Output: E2, E2, G2.

L5.2

Yeh loop teen functions banane ke liye hai jo 0, 1, 2 return kare. Explain karo actually kya hota hai aur isko default argument se fix karo (ek scope insight).

funcs = []
for i in range(3):
    def f():
        return i
    funcs.append(f)
print([g() for g in funcs])
Recall Solution L5.2 — actually prints

[2, 2, 2] Har f ek closure hai jo enclosing scope (yahan module) se i read karta hai call time par, creation time par nahi. Jab tak hum unhe call karte hain, loop khatam ho chuka hota hai aur i == 2, toh teeno 2 return karte hain. Fix — default argument se abhi value capture karo:

funcs = []
for i in range(3):
    def f(i=i):     # default is evaluated NOW, binding a fresh local i
        return i
    funcs.append(f)
print([g() for g in funcs])   # [0, 1, 2]

Default argument def time par evaluate hota hai aur per-function store hota hai, toh har f ka apna frozen i hota hai. Result: [0, 1, 2].


Recall Self-check: kaun sa keyword? (one-line drills)

Top-level function ke andar se module-level counter ko rebind karna ::: global Closure ke enclosing function mein rehne wale variable ko rebind karna ::: nonlocal Global list par .append() call karna ::: neither (mutation, rebinding nahi) Outer variable ko print() karna jise tum kabhi assign nahi karte ::: neither (pure read) x = x + 1 jahan x sirf module top par define hai ::: global (warna UnboundLocalError)

Connections

  • global and nonlocal keywords
  • Scope and LEGB rule
  • Functions in Python
  • Closures
  • Mutable vs Immutable objects
  • UnboundLocalError
  • Pure functions and side effects