LEGB describes Python’s variable-lookup order: local scope, enclosing function scopes, global scope, then built-ins. Python stops at the first matching name. Outside functions, lookup uses globals before built-ins; indentation alone does not create a new scope. section 7.5
Use the lookup order to reason about common scope behavior:
- A function-local assignment can hide a global with the same name without changing the global value. section 7.5
- A global name can shadow a built-in: assigning sum = 0 makes sum([10, 20, 30]) fail because Python finds the integer first. section 7.5
- An inner function can read a value from its enclosing function, and each outer-function call can preserve a separate value through a closure. section 7.11
- Use global to rebind a module-level name from a function, or nonlocal to update a name in an enclosing function. section 7.5
A closure with independent state
def foo(): call_counter = 0 def bar(y): nonlocal call_counter call_counter += 1 return f'y = {y}, call_counter = {call_counter}' return bar b = foo() print(b(10)) # y = 10, call_counter = 1
sum = 0
for i in range(5):
sum += i
print(sum)
print(sum([10, 20, 30]))
TypeError: 'int' object is not callable
Inspect the built-in-shadowing failure caused by assigning an integer to sum. section 7.5


