1. Introduction
A namespace is a mapping from names (identifiers) to objects, and a scope is the region of code where a particular namespace is directly accessible. Python resolves a variable name by searching through namespaces in a specific order, commonly summarized as LEGB: Local, Enclosing, Global, and Built-in.
Cricket analogy: Think of a cricket team's squad list (namespace) mapping player names to their roles; the scope is like knowing whether you're referring to the playing XI (local) or the entire franchise roster (global) when someone says "Kohli".
Understanding scope is essential for predicting which variable a piece of code actually refers to, especially when nested functions, loops, and modules define variables with the same name in different places.
Cricket analogy: If both Mumbai Indians and Chennai Super Kings have a player nicknamed "MS", commentators must scope the reference to the specific team's squad list to know which "MS" is batting.
2. Syntax
x = "global"
def outer():
x = "enclosing"
def inner():
global x # refers to the module-level x
nonlocal_demo = x
def inner2():
nonlocal x # refers to outer()'s x
x = "changed by inner2"
inner2()
3. Explanation
Local (L) scope is the innermost function's own namespace. Enclosing (E) scope refers to any enclosing function's namespace, relevant for nested functions (closures). Global (G) scope is the current module's top-level namespace. Built-in (B) scope contains names Python provides automatically, like len and print. When a name is referenced, Python searches these scopes in that exact order — Local, then Enclosing, then Global, then Built-in — and uses the first match it finds.
Cricket analogy: In a tournament, a batter's strike rate is looked up first in today's match card (Local), then the team's season stats (Enclosing), then the league table (Global), then the official ICC playing conditions (Built-in), stopping at the first source that has the number.
By default, assigning to a variable inside a function creates a new LOCAL variable, even if a variable with the same name exists at an outer scope; the outer variable is not modified. The global keyword tells Python that an assignment inside a function should modify the module-level variable instead of creating a local one. The nonlocal keyword does the equivalent for the nearest enclosing (non-global) function scope, which is essential for closures that need to modify a variable from an enclosing function.
Cricket analogy: If a substitute fielder scribbles a new score on their own scorecard without the umpire's approval, it's a local note only; declaring "global" like the official scorer updating the stadium screen is needed to change the match record everyone sees, while "nonlocal" is like a team's own scoreboard operator updating the previous over's tally.
A common gotcha is UnboundLocalError: if a function assigns to a variable anywhere in its body, Python treats that name as local for the ENTIRE function, even on lines before the assignment. So referencing the variable before the assignment (intending to read the outer/global value first) raises UnboundLocalError instead of silently reading the outer value. Declaring the name with global or nonlocal at the top of the function fixes this by telling Python not to treat it as local.
4. Example
x = "global x"
def outer():
x = "enclosing x"
def inner():
nonlocal x
x = "modified by inner"
print("inner:", x)
inner()
print("outer:", x)
outer()
print("global:", x)
counter = 0
def increment():
global counter
counter += 1
increment()
increment()
print("counter:", counter)
5. Output
inner: modified by inner
outer: modified by inner
global: global x
counter: 2
6. Key Takeaways
- Python resolves names using the LEGB order: Local, Enclosing, Global, Built-in.
- Assigning to a name inside a function makes it local by default, unless declared global or nonlocal.
- global lets a function assign to a module-level variable; nonlocal lets a nested function assign to an enclosing function's variable.
- Assigning to a variable anywhere in a function body makes it local for the whole function, so reading it earlier without global/nonlocal raises UnboundLocalError.
- Built-in scope supplies names like len, print, and range automatically, and is searched last.
Practice what you learned
1. What does the acronym LEGB stand for in Python's scope resolution?
2. By default, what happens when a function assigns a value to a variable that also exists at module (global) scope?
3. Which keyword allows a nested function to modify a variable from its enclosing (but non-global) function's scope?
4. In the Example, what is printed by print('global:', x) after outer() has run?
5. What error occurs if a function reads a variable before assigning to it later in the same function body, without declaring it global or nonlocal?
6. Which scope is searched LAST when Python resolves a variable name?
Was this page helpful?
You May Also Like
Functions in Python
How to define, call, and document reusable blocks of code with Python functions, including the def keyword and implicit None return.
Lambda Functions in Python
Writing small anonymous functions with lambda, using them with map/filter/sorted, and avoiding the late-binding closure trap in loops.
Recursion in Python
Writing recursive functions with proper base cases, understanding the call stack, and avoiding RecursionError from missing base cases or excessive depth.
Modules and Packages in Python
Learn how Python organizes code into reusable modules and packages, and how the import system locates and caches them.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics