nonlocal and Mutable State
Modify enclosing scope.
nonlocal and Mutable State is a free Python Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Python Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Reading vs writing enclosing variables
An inner function can freely read an enclosing variable, but if it tries to assign to that name, Python treats it as a new local variable instead. This often surprises beginners.
def outer():
count = 0
def inner():
return count
return inner()
print(outer())The assignment trap
Assigning to an enclosing name without declaring intent makes it local, so the outer variable is never updated. Here the change is lost.
def outer():
count = 0
def bump():
count = count + 1
try:
bump()
except UnboundLocalError as e:
print('Error:', e)
outer()The nonlocal keyword
nonlocal declares that a name refers to a variable in the nearest enclosing function scope, so assignments update that outer variable instead of creating a local one.
def outer():
count = 0
def bump():
nonlocal count
count += 1
bump()
bump()
return count
print(outer())A counter closure
With nonlocal you can build a stateful counter. Each call mutates the captured variable and remembers its progress.
def make_counter():
count = 0
def increment():
nonlocal count
count += 1
return count
return increment
c = make_counter()
print(c())
print(c())
print(c())Independent counters
Each counter keeps its own state because each closure captures a separate variable.
def make_counter():
count = 0
def inc():
nonlocal count
count += 1
return count
return inc
a = make_counter()
b = make_counter()
print(a(), a(), b())nonlocal vs global
nonlocal targets an enclosing function scope, while global targets the module level. Use nonlocal for closures, global for module-wide state.
total = 0
def add_global(n):
global total
total += n
add_global(5)
add_global(3)
print(total)Mutable state without nonlocal
If the enclosing value is a mutable object like a list or dict, you can mutate it in place without nonlocal, because you are not rebinding the name.
def make_logger():
history = []
def log(msg):
history.append(msg)
return history
return log
log = make_logger()
log('start')
print(log('stop'))An accumulator
Combining nonlocal with a closure gives a running accumulator that adds each value to a remembered total.
def make_accumulator():
total = 0
def add(n):
nonlocal total
total += n
return total
return add
acc = make_accumulator()
print(acc(10))
print(acc(5))
print(acc(100))A simple toggle
nonlocal makes it easy to flip a boolean state between calls.
def make_toggle():
on = False
def toggle():
nonlocal on
on = not on
return on
return toggle
t = make_toggle()
print(t(), t(), t())Resetting state
You can expose multiple inner functions that share the same enclosing state, for example one to add and one to reset.
def make_bank():
balance = 0
def deposit(n):
nonlocal balance
balance += n
return balance
def reset():
nonlocal balance
balance = 0
return balance
return deposit, reset
deposit, reset = make_bank()
print(deposit(50))
print(reset())nonlocal needs an existing variable
nonlocal requires the name to already exist in an enclosing scope; otherwise Python raises a SyntaxError at definition time. It cannot create a new outer variable.
def outer():
value = 'set'
def inner():
nonlocal value
value = 'changed'
inner()
return value
print(outer())Quick Check
Inside a nested function you want to reassign a variable from the enclosing function. Which keyword do you use?
Recap: nonlocal and Mutable State
Summary:
- Assigning to an enclosing name normally creates a new local;
nonlocalprevents that. nonlocaltargets the enclosing function scope;globaltargets the module.- Mutating a mutable object in place needs no declaration.
- Closures with
nonlocalbuild counters, accumulators, and toggles that remember state.
def make_counter():
n = 0
def inc():
nonlocal n
n += 1
return n
return inc
c = make_counter()
print(c(), c())Frequently asked questions
Is the “nonlocal and Mutable State” lesson free?
Yes — the full text of “nonlocal and Mutable State” is free to read here on the web, and the Python Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Python Academy course, upgrade to CoddyKit PRO.
What will I learn in “nonlocal and Mutable State”?
Modify enclosing scope. You practise Python Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Python Academy?
No prior experience is required. Python Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “nonlocal and Mutable State” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Python Academy lesson?
Yes. Every Python Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- First-Class Functions
- Closures and Free Variables
- nonlocal and Mutable State
- Partial Functions