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