The LEGB Rule
When Python encounters a variable name, it searches in this order: Local (inside the current function), Enclosing (outer function in nested functions), Global (module-level), Built-in (Python's built-in names like len, print, range).
x = "global" # G - global scope
def outer():
x = "enclosing" # E - enclosing scope
def inner():
x = "local" # L - local scope
print(x) # Finds "local" first
inner()
print(x) # Finds "enclosing"
outer()
print(x) # Finds "global"
The global Keyword
To modify a global variable inside a function, declare it with the global keyword.
count = 0 # Global
def increment():
global count # Tell Python to use the global count
count += 1
increment()
increment()
increment()
print(count) # 3 - global was modified
Using global is generally discouraged. Prefer passing values as arguments and returning them instead.
The nonlocal Keyword (Closures)
In nested functions, nonlocal refers to the enclosing function's variable (not global).
def make_counter():
count = 0
def counter():
nonlocal count # Refers to outer function's count
count += 1
return count
return counter
my_counter = make_counter()
print(my_counter()) # 1
print(my_counter()) # 2
print(my_counter()) # 3
Built-in Scope
Built-in scope contains Python's built-in functions and constants. Be careful not to shadow them with your own variable names.
# ❌ Don't shadow built-ins!
list = [1, 2, 3] # Overwrites the built-in list!
print = "hi" # Overwrites print! Now you can't print!
# ✅ Use descriptive names
my_list = [1, 2, 3]
message = "hi"
print(message) # Works fine
The LEGB Rule: Where Python Looks Up a Name
When you use a variable, Python searches four scopes in order — Local, Enclosing, Global, Built-in — and uses the first match. Understanding LEGB explains most "why is this variable that value?" confusion.
x = "global"
def outer():
x = "enclosing"
def inner():
print(x) # finds "enclosing" (E) before "global" (G)
inner()
Assigning needs global / nonlocal
Reading an outer variable is automatic; rebinding one is not. Assign to a name inside a function and Python treats it as local unless you declare otherwise:
count = 0
def bump():
global count # without this, "count += 1" raises UnboundLocalError
count += 1
def make_counter():
n = 0
def inc():
nonlocal n # rebind the enclosing n, not create a new local
n += 1; return n
return inc
Common trap: count += 1 without global fails because the += makes count a local, then reads it before assignment. Prefer returning values over mutating globals — globals make code hard to test and reason about.
🏋️ Practical Exercise
Explore variable scope:
- Define a variable inside a function and confirm it is not visible outside.
- Read a global variable from inside a function (no keyword needed).
- Use the
globalkeyword to modify a module-level variable from a function. - Create a closure with an inner function and use
nonlocalto update an enclosing variable.
🔥 Challenge Exercise
Build a counter factory: a function make_counter() that returns an inner function which, each time it is called, increments and returns a count. Use nonlocal so the inner function updates the enclosing variable. Create two independent counters and show they don’t interfere. Then write a small example that demonstrates the full LEGB lookup order with a name defined at several levels.
📋 Summary
- Scope determines where a name is visible; Python resolves names using the LEGB rule.
- LEGB = Local → Enclosing → Global → Built-in, searched in that order.
- Assigning to a name inside a function creates a new local unless declared
globalornonlocal. globallets a function rebind a module-level variable.nonlocallets a nested function rebind a variable in the enclosing (but non-global) scope.- A closure is an inner function that remembers variables from its enclosing scope.
Interview Questions on Scope
- What is variable scope in Python?
- What is the LEGB rule?
- What does the
globalkeyword do? - What does the
nonlocalkeyword do and how does it differ fromglobal? - What is a closure?
- Why can you read a global variable in a function but not assign to it without
global? - What is the built-in scope?
Related Topics
FAQ
It is the order Python searches for a name: Local (inside the current function), Enclosing (any outer functions), Global (module level), and Built-in (Python’s own names like len). The first match wins.
global and nonlocal? +global binds a name to the module-level scope, letting a function modify a top-level variable. nonlocal binds to the nearest enclosing function scope, used in closures to modify a variable in an outer (but not global) function.
global? +Reading falls back through LEGB and finds the global. But assigning to a name inside a function makes Python treat it as a new local for the whole function, shadowing the global — unless you declare global first.
A closure is a nested function that captures and remembers variables from its enclosing scope even after that outer function has finished. It is the basis for decorators and factory functions like a counter generator.

