1.2.30 · D3 · HinglishIntroduction to Programming (Python)

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

2,675 words12 min read↑ Read in English

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

Shuru karne se pehle, ek shared mental picture. Har "scope" sirf ek labelled box hai jo names hold karta hai. Jab Python koi name padhta hai, woh in boxes ko ek fixed order mein walk karta hai aur pehla box grab karta hai jiske paas woh name hai.

Figure — Variable scope — LEGB rule (Local, Enclosing, Global, Built-in)
  • L = woh box jo jis moment function run karna shuru karta hai create hota hai.
  • E = us function ka box jo current function ko wrap karta hai.
  • G = poori file (module) ke liye box.
  • B = ek permanent box jo Python ke saath aata hai (len, print, range, sum, …).

Yeh picture open rakho. Neeche har example sirf "kaun sa box jeet ta hai, aur kyun" hai.


The scenario matrix

Variable scope mein thode se axes hain jo fully determine karte hain kya hoga. Har real program in cells ka combination hota hai.

Axis Cases jo hume cover karne hain
Operation pure read · write bina keyword ke · write with global · write with nonlocal
Kaun sa box read jeeeta hai L mein mila · E mein mila · G mein mila · B mein mila · kahin nahi mila (NameError)
The assignment trap read-before-write us name ki jo assignment ne local banaya (UnboundLocalError)
Shadowing L/E/G mein ek name ek built-in (B) ko hide karta hai
Degenerate / zero cases function jo kuch assign nahi karta · empty enclosing scope · nonlocal bina target ke · ek name delete karna
Mutation vs rebinding list ka contents change karna (scope keyword ki zaroorat nahi) vs name ko new list pe point karna (global/nonlocal chahiye)
Real-world twist ek counter jo calls ke across share hota hai (closure)
Exam twist loop/if blocks scope nahi banate; comprehensions banate hain

Neeche, har example us cell(s) ke saath tagged hai jo woh cover karta hai. End tak, upar ka har cell ticked ho jayega.


Example 1 — Read har box mein baari baari resolve hota hai

Steps

  1. inner() run karo. Python ko print ke liye tag read karna hai. Yeh step kyun? print(tag) ek read hai, toh L→E→G→B walk shuru hoti hai.
  2. L mein dekho (inner ka box). tag = "L-inner" wahan hai → ruko. Yeh step kyun? Pehla match jeet ta hai; Python kabhi E ya G nahi kholega.
  3. Result: "L-inner".

Ab inner se tag = "L-inner" delete karo. Read empty L box se past E mein walk karta hai aur "E-outer" paata hai. Woh bhi delete karo, aur yeh G mein walk karta hai aur "G-file" paata hai.

Verify: teeno lines present hone par → L-inner. L hatane par → E-outer. L aur E hatane par → G-file.

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

Example 2 — Built-in tak poora fall karna

Steps

  1. count_chars ke andar, len read karo. Yeh L mein nahi hai (sirf word hai), E mein nahi (koi enclosing function nahi), G mein nahi (file koi len define nahi karti). Yeh step kyun? Hume B se pehle L, E, G exhaust karna padega — yahi poora order hai.
  2. B mein mila → len Python ka built-in string length function hai. len("hi") = 2. Yeh step kyun? Yahi reason hai ki len, print, range bina import kiye kaam karte hain: yeh permanently B mein rehte hain.
  3. Ab print(banana). banana read karo: L, E, G, ya B mein nahi. Yeh step kyun? Jab charon boxes fail ho jaate hain, toh try karne ke liye kuch nahi bachta.
  4. Python NameError: name 'banana' is not defined raise karta hai.

Verify: len("hi") = 2. banana har jagah undefined hai → NameError.


Example 3 — The assignment trap (UnboundLocalError)

Steps

  1. Compile time par (function ke kabhi run karne se pehle), Python add_tip scan karta hai aur total = … dekhta hai. Yeh step kyun? Kisi name ke bare assignment se woh poori function body ke liye Local flag ho jaata hai — ek baar decide hota hai, pehle se, line by line nahi.
  2. Toh total poore add_tip mein ek local name hai. Global total = 100 ab andar invisible hai. Yeh step kyun? Local-creation rule us specific name ke liye L→E→G walk ko override karta hai.
  3. total + 10 execute karo. Right-hand side compute karne ke liye hume local total read karna hoga — lekin abhi tak uski koi value nahi hai (assignment abhi complete nahi hui). Yeh step kyun? Read write complete hone se pehle hota hai, aur fall back karne ke liye koi doosra total nahi hai.
  4. Python UnboundLocalError: local variable 'total' referenced before assignment raise karta hai.
Figure — Variable scope — LEGB rule (Local, Enclosing, Global, Built-in)

Verify: add_tip() call karne par UnboundLocalError aata hai, kabhi 110 return nahi karta.


Example 4 — global se fix karna

Steps

  1. global total Python ko batata hai: "is function ke liye, total G name hai — local mat banao." Yeh step kyun? Yeh Example 3 ke compile-time local-creation rule ko cancel kar deta hai.
  2. Ab total + 10 global 100 padhta hai → 110, aur assignment global ko 110 se rebind karti hai. Yeh step kyun? Local rule gone hone se, read aur write dono same G box pe point karte hain.
  3. add_tip() 110 return karta hai; baad mein module-level total bhi 110 hai.

Verify: add_tip() = 110, aur global total = 110 baad mein.


Example 5 — nonlocal se enclosing state fix karna

Steps

  1. make_counter() run hota hai, apne box mein n = 0 create karta hai, step define karta hai, step return karta hai (use c kaho). Yeh step kyun? make_counter finish hone ke baad bhi, uska n box survive karta hai kyunki step abhi bhi usse point kar raha hai — yahi ek closure hai.
  2. Pehla c(): nonlocal n name ko nearest enclosing box (E) pe aim karta hai, L pe nahi, G pe nahi. Yeh step kyun? nonlocal ke bina, n += 1 ek fresh local n banana try karta aur bilkul Example 3 ki tarah UnboundLocalError deta.
  3. n += 1 E ka 0 padhta hai, 1 write back karta hai, 1 return karta hai. Doosra call → 2. Teesra → 3.

Verify: c(), c(), c() (1, 2, 3) deta hai.


Example 6 — Built-in ko shadow karna

Steps

  1. Line 1: sum read karo → G mein abhi nahi → B mein mila (built-in) → sum([1,2,3]) = 6. Yeh step kyun? Shadowing se pehle, B hi jagah hai jahan sum rehta hai.
  2. sum = 10 G box mein sum name daalta hai. Yeh step kyun? Ab L→E→G→B walk sum G mein B tak pahunchne se pehle paata hai — built-in hidden hai, delete nahi.
  3. sum + 5 G ka sum = 10 padhta hai → 15.
  4. sum([1,2,3]) G ka sum = 10 padhta hai, phir 10(...) call karne ki koshish karta hai. Yeh step kyun? Ek integer callable nahi hai → TypeError.

Verify: original sum([1,2,3]) = 6; shadowing ke baad, sum + 5 = 15; sum([1,2,3]) TypeError raise karta hai.


Example 7 — Mutation ke liye koi keyword nahi chahiye

Steps

  1. add_book: shelf.append(3) shelf ka ek read hai (list dhundhne ke liye), phir ek method call jo use in place mutate karta hai. Yeh step kyun? Yahan koi assignment shelf = … nahi hai, toh local-creation rule kabhi fire nahi hota. Read L→E→G walk karta hai, list paata hai, aur .append usi object ko edit karta hai → [1, 2, 3]. Dekho Mutable vs Immutable arguments.
  2. replace_shelf: shelf = [9, 9] ek assignment haishelf us function ka local hai. Yeh step kyun? Yeh local box mein ek brand-new list banata hai aur function end hone par usse throw away kar deta hai; global list untouched rehti hai.
  3. Final global shelf = [1, 2, 3].

Verify: dono calls ke baad, shelf = [1, 2, 3].


Example 8 — Degenerate nonlocal bina target ke

Steps

  1. nonlocal m ek enclosing function ke box mein m variable demand karta hai. Yeh step kyun? nonlocal sirf ek existing E name ko reuse karta hai; woh ek naya create nahi kar sakta.
  2. outer ke body mein kahin bhi m nahi hai → koi E target nahi hai. Yeh step kyun? Yeh empty-enclosing-scope degenerate case hai.
  3. Python ise compile time par reject karta hai: SyntaxError: no binding for nonlocal 'm' found.

Verify: code ek SyntaxError hai (compile-time), NameError/UnboundLocalError nahi.


Example 9 — Exam twist: blocks scope nahi banate, comprehensions banate hain

Steps

  1. if/for blocks Python mein koi naya box nahi banate. msg report ke single local box mein rehta hai. Yeh step kyun? C ya Java ke unlike, Python sirf function, module, aur comprehension se scope karta hai — {}/indentation blocks se nahi.
  2. report(True): if run hota hai, msg = "yes" local box fill karta hai → yes print hota hai.
  3. report(False): if skip ho jaata hai, toh msg kabhi assign nahi hua → use padhna → UnboundLocalError. Yeh step kyun? Example 3 jaisa hi trap: assignment use local mark karta hai, lekin is run ne kabhi write execute nahi ki.
  4. Comprehension [k*k for k in range(4)] [0, 1, 4, 9] deta hai, aur uska loop variable k apna box pata hai. Yeh step kyun? Comprehensions teen scope-makers mein se ek hain, toh k module mein leak nahi hota.
  5. Module level par print(k)NameError, kyunki k G mein kabhi exist nahi kiya.

Verify: report(True)yes; report(False)UnboundLocalError; [k*k for k in range(4)] = [0,1,4,9]; module-level print(k)NameError.



Active Recall

Recall Scenarios par self-test
  1. Example 3 mein, Python kab decide karta hai ki total local hai — compile time ya run time?
  2. shelf.append(3) ko global ki zaroorat kyun nahi, lekin shelf = [9,9] ko hogi?
  3. Kaun sa error class ek nonlocal bina enclosing target ke raise karta hai, aur kab?
  4. report(False) crash kyun karta hai jabki report(True) theek hai?
  5. sum = 10 ke baad, sum([1,2,3]) NameError ki jagah TypeError kyun deta hai?

Connections

  • Parent topic (Hinglish) — core LEGB rule jise yeh examples exercise karti hain.
  • Functions and Parameters — har call hi hai jo L box create karta hai.
  • Closures and Nested Functions — Example 5 ka counter E ke upar ek live closure hai.
  • Namespaces and the dict model — yahan har box actually ek dictionary hai.
  • Mutable vs Immutable arguments — Example 7 mutate-vs-rebind distinction hai.
  • NameError and UnboundLocalError — upar catalogue kiye gaye do crashes.
  • Modules and import — G box populate karta hai jise Examples 4, 6, 7 read karte hain.