LEGB Rule
When you use a variable, Python doesn’t just look everywhere at once. It follows a strict search order called LEGB.
- Local (L): Variables defined inside the current function.
- Enclosing (E): Variables in the “Parent” function (Nested functions).
- Global (G): Variables defined at the very top level of your file.
- Built-in (B): Reserved words living inside Python itself (like
print,len, orrange).
If Python reaches the “Built-in” layer and still hasn’t found the variable, it finally gives up and throws a NameError.
Enclosing Scope
In modern Python, we often put functions inside other functions. The Enclosing Scope is the space belonging to the outer function.
The inner function can “see” everything in the outer function, but the outer function cannot see inside the inner one.
def outer_function():
treasure = "Gold" # Enclosing variable
def inner_function():
# This works! Inner can see outward.
print(f"I found the {treasure}!")
inner_function()
outer_function()
Closures
A Closure happens when an inner function “remembers” the variables from its enclosing scope, even after the outer function has finished running.
Think of it like this: The outer function gives the inner function a backpack full of data and then leaves. The inner function keeps that backpack forever.
def make_multiplier(n):
# This is the 'Parent' scope
def multiplier(x):
# x is local, but n is 'trapped' in the backpack
return x * n
return multiplier
# Create a 'doubler' (it carries a backpack where n=2)
doubler = make_multiplier(2)
# Create a 'tripler' (it carries a backpack where n=3)
tripler = make_multiplier(3)
print(doubler(5)) # 10
print(tripler(5)) # 15
Avoiding Name Collisions
What happens if you have the same name in different layers? The innermost layer always wins.
name = "Global"
def outer():
name = "Enclosing"
def inner():
name = "Local"
print(name) # Prints "Local"
inner()
outer()
If you comment out name = "Local", Python will move one step out and print "Enclosing". If you comment that out too, it prints "Global".
Always try to keep variables as Local as possible. It prevents your “backpacks” from getting cluttered and causing bugs.
Using Variables from Outer Scopes
By default, you can read a variable from a higher scope, but you cannot change it. If you try to change a global variable inside a function, Python will simply create a new local variable with the same name and leave the global one alone.
To fix this, we use two special keywords: global and nonlocal.
global Keyword
Use this when a function needs to modify a variable sitting at the very top level of your file.
score = 0 # Global
def increase_score():
global score # "Hey Python, use the one from global scope"
score += 1
increase_score()
print(score) # Output: 1
nonlocal Keyword
Use this inside nested functions. It tells the inner function to modify a variable in the “Parent” function (the Enclosing scope).
def outer():
count = 0 # Enclosing variable
def inner():
nonlocal count # "Hey Python, use my parent's variable!"
count += 1
print(f"Inner count: {count}")
inner()
outer()