Theory
दो totals, zero conflict। फिर एक crash।
ResultDesk के पास अब db.py और reports.py हैं, और दोनों total नाम का एक variable define करते हैं। कुछ नहीं टूटता। दो files, वही नाम, कोई झगड़ा नहीं। कैसे?
फिर एक teammate आपकी grades.py को एक tools folder में move करता है, और अचानक import grades मर जाता है: ModuleNotFoundError, हालाँकि file साफ़ मौजूद है।
दोनों mysteries की एक ही जड़ है: Python नामों के maps रखता है, और जगहों की lists देखने के लिए। Maps (namespaces) और list (search path) सीखिए और दोनों mysteries घुल जाते हैं।
Theory
वही नाम, अलग registers
तीन classes में Riya नाम की तीन students पढ़ती हैं। कभी कोई confusion नहीं: हर class का register अपनी छोटी दुनिया है, और "Riya" का मतलब है कोई specific per register।
एक namespace एक register है: names को असली objects में एक mapping। हर function एक रखता है (local), हर module एक रखता है (global), और Python ख़ुद एक रखता है (built-in, जहाँ print और len रहते हैं)। अलग-अलग registers में identical names कभी collide नहीं करते।
Theory
Scope और LEGB lookup
Scope सवाल है: जब code `total` कहता है, Python कौन सा register check करता है?
Lookup order LEGB है, first hit जीतता है:
- Local: current function के अंदर बने नाम
- Enclosing: outer function, अगर nested हो
- Global: module के अपने नाम
- Built-in: print, len, sum...
एक तेज़ edge: function के अंदर assign करना एक LOCAL नाम बनाता है। किसी function के अंदर से एक module-level नाम rebind करने के लिए आपको पहले global total declare करना होगा।
Practical
बारह lines में LEGB
total = 100 # G: module (global) namespace
def report():
total = 5 # L: a NEW local name, global untouched
print(total) # 5 (Local wins the lookup)
report()
print(total) # 100 (the global was never changed)
def reset():
global total # opt in to rebinding the global
total = 0
reset()
print(total) # 0
# Built-in namespace is the LAST stop:
# len, print, sum live there... until you shadow them:
# sum = 0 <- now sum() crashes: 'int' is not callable
This example runs in Gri-Learn on the web, where you can edit it and see the output.
Theory
Packages और PYTHONPATH
एक package modules का एक folder है, एक __init__.py file से marked:
resultdesk/
├── __init__.py
├── db.py
└── reports.py
Folders mirror करते dots से import कीजिए: from resultdesk import db।
और Python modules और packages कहाँ ढूँढता है? सिर्फ़ sys.path की directories: current folder, standard locations, plus कुछ भी जो आप PYTHONPATH environment variable से जोड़ें (export PYTHONPATH=/home/riya/tools)। Teammate का crash: tools folder उस list पर नहीं था।
Quiz
Module level पर x = 10 है। एक function x = 99 करता है (कोई global statement नहीं) और module बाद में x print करता है। क्या print होता है, और क्यों?
- 10: assignment ने एक अलग LOCAL x बनाया; global untouched रहा
- 99: functions हमेशा surrounding variable modify करते हैं
- Error: x दो बार defined है
- 0: Python shadowed variables reset करता है
Show the answer
10: assignment ने एक अलग LOCAL x बनाया; global untouched रहा
Function के अंदर assignment function के अपने namespace में एक local नाम जन्म देता है; module-level x को इसके बारे में कभी पता नहीं चलता। Global बदलने के लिए explicit global x declaration चाहिए। Option B उन languages को describe करता है जो Python होने से मना करता है; एक ही नाम रखते दो namespaces normal है, error नहीं। यह exact trace, इन्हीं exact दो numbers के साथ, एक exam regular है।
Think first
Teammate का import fix कीजिए
grades.py अब /home/riya/tools में रहती है, और आपकी script (कहीं और से चलती हुई) को import grades चाहिए। tap करने से पहले: import को सफल बनाने के DO अलग तरीक़े नाम दीजिए।
Show the answer
1. PYTHONPATH set कीजिए: run करने से पहले export PYTHONPATH=/home/riya/tools: folder उस shell में हर Python run के लिए sys.path में जुड़ता है।
2. Code में append कीजिए: import से पहले import sys; sys.path.append('/home/riya/tools'): एक per-script fix।
(असली projects के लिए तीसरा, cleanest: tools को एक proper installed package बनाइए।) दोनों तरीक़ों का principle: Python सिर्फ़ sys.path search करता है; imports list से absence से fail होते हैं, files के मौजूद न होने से नहीं।
Watch out
Shadowing: silent namespace crime
एक script के top पर sum = 0 चुपचाप built-in sum() दबा देता है: पचास lines बाद sum(scores) 'int' object is not callable के साथ फट जाता है और कोई hint नहीं क्यों।
LEGB इसे explain करता है: आपका Global sum अब Built-in तक पहुँचने से पहले lookup जीत जाता है। पिछले lesson के csv.py द्वारा csv module shadow करने जैसी ही बीमारी: एक namespace level दूसरे को छुपाता है। Built-in names (sum, list, max, id) को reserved समझिए।
Theory
आगे की units के लिए यह क्यों मायने रखता है
आप जो भी import लिखेंगे (अगला lesson sqlite3, Unit 4 में pandas) sys.path से succeed या fail होता है, और आप जो भी NameError debug करेंगे वह LEGB पूछ रहा है आपने वह नाम असल में किस register में डाला। दो mental tools, दोनों invisible उस दिन तक जब वे आपका एक घंटा बचाते हैं।
Summary
Key takeaways
- एक namespace names को objects में map करता है; local, global और built-in namespaces साथ रहते हैं।
- Lookup order LEGB है: Local, Enclosing, Global, Built-in; first hit जीतता है।
- Function में assignment एक local नाम बनाता है; global rebind करने को global keyword चाहिए।
- एक package = __init__.py वाला modules का एक folder; import dots folders mirror करते हैं।
- Python सिर्फ़ sys.path search करता है; PYTHONPATH इसमें directories जोड़ता है।
- Built-ins (sum, list, max) या module names को कभी shadow मत कीजिए।
- Memory hook: वही नाम, अलग class registers।