nonlocal
A nested function can read its outer function’s variables for free. To assign to one, declare it nonlocal — otherwise the assignment creates a new local.
nonlocal
def outer(): x = 0 def inner(): nonlocal x x += 1
several names
nonlocal a, b
Use for
Counters, accumulators and flags kept in a closure
Result
a declaration — no value; the name refers to the nearest enclosing function’s variable
Pairs with
def (nested), global, lambda, decorators
Watch out
the name must already be bound in an enclosing FUNCTION — module globals do not count
Demo
Live evaluation
Each call to c rebinds count in make_counter’s scope, which outlives the call that created it.
Try:
Inputs
startintstarting value
Code
def make_counter(start): count = start def bump(): nonlocal count count += 1 return count return bump c = make_counter(0) (c(), c(), c())
Result
(1, 2, 3)
make_counter has already returned when c() runs, yet count survives: the inner function holds a reference to the variable (a closure cell), and nonlocal lets it write to that cell instead of creating a fresh local.
Syntax slots
| Name | Type | Required | Description |
|---|---|---|---|
| name | name | yes | One or more identifiers bound in an enclosing function (not the module). Resolved at compile time. |
Common patterns
Counter closure
State without a class.
def make_counter(): count = 0 def bump(): nonlocal count count += 1 return count return bump
Decorator that counts calls
The wrapper updates a variable of the decorator.
def counted(func): calls = 0 def wrapper(*args, **kwargs): nonlocal calls calls += 1 return func(*args, **kwargs) return wrapper
Flag set by a callback
An inner helper reports back to its outer function.
def scan(items): found = False def check(x): nonlocal found if x < 0: found = True for x in items: check(x) return found
Examples
1. A counter closure
def make_counter():
count = 0
def bump():
nonlocal count
count += 1
return count
return bump
c = make_counter()
c()
c()
Returns
22. Reading needs no declaration
def outer():
x = 10
def inner():
return x + 1
return inner()
outer()
Returns
113. Nearest enclosing function wins
def a():
x = 'a'
def b():
x = 'b'
def c():
nonlocal x
x = 'c'
c()
return x
return b(), x
a()
Returns
('c', 'a')4. Mutating needs no nonlocal
def make():
seen = []
def add(v):
seen.append(v)
return seen
return add
add = make()
add(1)
add(2)
Returns
[1, 2]5. The name must exist in an enclosing function
compile('def f():\n nonlocal x', '<demo>', 'exec')
Returns
SyntaxError: no binding for nonlocal 'x' found6. Not at module level
compile('nonlocal x', '<demo>', 'exec')
Returns
SyntaxError: nonlocal declaration not allowed at module level7. Closures are separate
def make_counter():
count = 0
def bump():
nonlocal count
count += 1
return count
return bump
c1, c2 = make_counter(), make_counter()
(c1(), c1(), c2())
Returns
(1, 2, 1)Pitfalls
1. Updating an outer variable with +=
total += n assigns, so total becomes local to add — and is read before it has a value.
no declaration
def make_acc(): total = 0 def add(n): total += n return total return add make_acc()(5)
UnboundLocalError: cannot access local variable 'total' where it is not associated with a value
nonlocal total
def make_acc(): total = 0 def add(n): nonlocal total total += n return total return add make_acc()(5)
5
2. A plain assignment silently creates a local
No error at all — the inner function just sets its own variable, and the outer one never changes.
assignment only
def outer(): status = 'idle' def start(): status = 'running' start() return status outer()
'idle'
nonlocal status
def outer(): status = 'idle' def start(): nonlocal status status = 'running' start() return status outer()
'running'
3. nonlocal for a module-level variable
nonlocal only searches enclosing functions. A module variable needs global.
nonlocal
compile('x = 0\ndef f():\n nonlocal x\n x = 1', '<demo>', 'exec')
SyntaxError: no binding for nonlocal 'x' found
global
x = 0 def f(): global x x = 1 f() x
1
When to use
Use it
- Small stateful closures: counters, accumulators, memo flags
- Decorators that keep per-function state
- Helper functions nested inside a function that need to update its variables
Reach for something else
- State with several fields or methods → a class
- Module-level variables → global (or better, parameters and return values)
- Only mutating an outer list or dict → no declaration needed
Notes
CPython impl
The shared variable lives in a cell object: the outer function uses MAKE_CELL / STORE_DEREF, the inner one LOAD_DEREF / STORE_DEREF
Scope
nonlocal skips the local scope and searches enclosing function scopes from the nearest outward; class bodies and the module are never searched
Python 2
Python 2 had no nonlocal — the usual workaround was a mutable container like count = [0]
FAQ
global name refers to the module-level variable. nonlocal name refers to the variable of the nearest enclosing function that binds it. Both let you assign to a name that would otherwise become local.