Why this matters
When you write x inside a function, which x do you get? The one you just assigned, one defined at the top of the file, or a built-in? The rules that answer this are called scope. Getting them right is what lets thousands of functions in a large program each use names like i, result and total without stepping on each other. Getting them wrong produces some of the most confusing errors beginners meet, especially UnboundLocalError. The rules are short and precise, so learn them once.
Namespaces: where names live
A namespace is a mapping from names to objects. Python has several, each with a lifetime:
- Local: each function call gets a fresh one, stored in its frame, discarded when the call returns.
- Global: one per module (file), created when the module runs. Names assigned at the top level of a file live here.
- Built-in: one for the whole interpreter, holding
print,len,int,ValueErrorand friends.
You can look at two of them directly:
x = 1
def f():
y = 2
print("locals:", locals())
f()
print("x" in globals(), "y" in globals())
locals: {'y': 2}
True False
y existed only in f's local namespace, for the duration of the call.
The LEGB rule
When Python looks up a name to read it, it searches up to four scopes in order and uses the first match:
L Local names assigned in the current function
E Enclosing locals of any outer functions this one is nested in
G Global names at the top level of the module
B Built-in print, len, range, ...
If none has the name: NameError: name 'x' is not defined.
greeting = "hello" # global
def outer():
name = "Ada" # local to outer, enclosing for inner
def inner():
punct = "!" # local to inner
return greeting + ", " + name + punct # G, E, L
return inner()
print(outer())
print(len(outer())) # len found in Builtins
hello, Ada!
11
Assignment makes a name local
The rule for reading is LEGB. The rule for assigning is simpler and stricter:
Note: Any name assigned anywhere inside a function (by
=,+=, aforloop variable, adef, animport) is local to that function, for the whole function body, unless declaredglobalornonlocal.
This decision is made by the compiler, when the function's bytecode is built, not while it runs. Disassembling shows it:
import dis
x = 10
def show():
print(x)
def shadow():
x = 5
print(x)
dis.dis(show)
dis.dis(shadow)
In show the bytecode uses LOAD_GLOBAL x, while in shadow it uses STORE_FAST x and LOAD_FAST x. "Fast" locals are stored in numbered slots in the frame, not in a dictionary, which is one reason local variable access is quicker than global access.
So assigning a name inside a function never changes a global of the same name:
x = 10
def f():
x = 99 # a new local x
f()
print(x) # 10
UnboundLocalError
Combine "assignment makes it local everywhere in the function" with reading before assigning:
count = 0
def bump():
count = count + 1
return count
bump()
Traceback (most recent call last):
File "demo.py", line 7, in <module>
bump()
File "demo.py", line 4, in bump
count = count + 1
^^^^^
UnboundLocalError: cannot access local variable 'count' where it is not associated with a value
Because bump assigns count, the compiler made count local. The right-hand side reads the local, which has not been given a value yet. Python does not fall back to the global; the scope was fixed at compile time.
Changing globals: global (and why to avoid it)
The global declaration tells the compiler "this name refers to the module-level one":
count = 0
def bump():
global count
count = count + 1
bump(); bump()
print(count) # 2
It works, but global mutable state makes programs hard to reason about and test: any function anywhere might change it, and the result of a call depends on history. The cleaner design passes state in and returns the new state:
def bump(count):
return count + 1
count = 0
count = bump(count)
count = bump(count)
print(count) # 2
Reading global constants is fine and common. By convention they are written in capitals: MAX_RETRIES = 3.
Enclosing scopes and nonlocal
Functions can be defined inside other functions. The inner function can read the outer function's locals (the E in LEGB), even after the outer function has returned:
def make_multiplier(factor):
def multiply(n):
return n * factor # factor comes from the enclosing scope
return multiply
triple = make_multiplier(3)
print(triple(10)) # 30
How can factor still exist after make_multiplier returned and its frame was discarded? CPython notices at compile time that factor is used by an inner function and stores it in a cell, a small object that the inner function keeps a reference to. The inner function together with its captured cells is called a closure. Module 13 explores closures in depth.
To assign to an enclosing variable, declare it nonlocal; otherwise the assignment would create a new local in the inner function:
def make_counter():
count = 0
def step():
nonlocal count
count += 1
return count
return step
c = make_counter()
print(c(), c(), c()) # 1 2 3
Shadowing built-ins
Since Global is searched before Built-in, a global named like a built-in shadows it:
list = [1, 2, 3] # shadows the built-in list type
print(list("abc"))
TypeError: 'list' object is not callable
Common victims: list, dict, str, len, sum, max, min, input, id, type. Python does not warn you; choose different names (items, total, length). If you do it in the REPL, del list removes your global and the built-in reappears.
Loop variables and blocks
Unlike many languages, Python's if, for and while blocks do not create a scope. Only functions (and classes, comprehensions and modules) do:
for i in range(3):
last = i * 10
print(i, last) # 2 20 (still visible after the loop)
Common mistakes
- Expecting an assignment inside a function to update a global. It creates a local. Return the value instead.
UnboundLocalErrorfrom reading and assigning the same name in a function. Pass the value as a parameter.- Shadowing built-ins with variable names, producing
'int' object is not callableor'list' object is not callablefar from the cause. - Using
globalfor things that should be parameters. If a function needs a value, ask for it as an argument.
Recap
- Each call has a local namespace; each module a global one; the interpreter one built-in namespace.
- Reading a name searches Local, Enclosing, Global, Built-in, in that order.
- Assigning a name anywhere in a function makes it local for the whole function, decided at compile time.
globalandnonlocalredirect assignment to the module or enclosing scope; prefer parameters and return values.- Blocks like
ifandfordo not create scopes; naming a variablelistorlenshadows the built-in.
Going further: read "Python Scopes and Namespaces" in the official tutorial (section 9.2). Try import builtins; print(dir(builtins)) to see every built-in name you might accidentally shadow.