LEGB rule is the rule for name resolution in Python. The abbreviation stands for:
len, list, etc.).When Python encounters a variable, it first looks locally, then in enclosing scopes, then globally, and finally in the namespace of built-in objects:
def outer(): x = 'enclosing' def inner(): x = 'local' print(x) inner() outer() # 'local'
If the assignment of x is removed inside inner(), Python will take x from the enclosing scope (outer). If there is no variable there, it searches globally, then in built-ins.
How would the function's behavior change if you forget to declare
nonlocalorglobalwhen modifying a variable from an outer scope?
Answer:
If you try to modify an outer scope variable inside an inner function without declaring it nonlocal (or global — if the variable is at the module level), Python will create a new local variable, not changing the outer one.
Example:
x = 10 def foo(): x = 20 # This is a new local x, the global one is not changed foo() print(x) # 10
To change the global x:
def foo(): global x x = 20
For variables in the enclosing function — use nonlocal.
Story 1
In an educational project, nested functions were used to count the number of calls. The developer wrote:
def counter(): count = 0 def inc(): count += 1 return count return inc
But it raised an UnboundLocalError because count was considered a new variable inside inc() (a local count was created). The solution: declare count as nonlocal.
Story 2
In a web application, they wanted to modify a globally defined cache in a handler:
cache = {} def add_to_cache(key, value): cache[key] = value
However, if they tried to completely overwrite cache inside the function, for example cache = {key: value}, this would create a new local cache unrelated to the global one due to the absence of global cache.
Story 3
In a large ETL system, a bug occurred: programmers left the variable result without explicit initialization inside a function, expecting it to take the value from the outer scope. However, after several iterations, the result began to diverge because inside there was an operation result += value rather than result = result + value (without nonlocal/global) — and result was re-initialized on each call.