Is it possible to modify a variable in python that is in an outer enclosing, but not global, scope?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Yes. In Python 3, the direct way to rebind a variable from an enclosing, non-global scope is the nonlocal keyword. Without nonlocal, assignment inside the inner function creates a new local variable instead of changing the binding from the outer function.
The Scope Rule Behind The Problem
Python resolves names using the LEGB rule:
- local
- enclosing
- global
- built-in
Reading an enclosing variable is easy. Rebinding it is the part that surprises people.
Consider this example:
This raises UnboundLocalError. The reason is that count += 1 is an assignment. Once Python sees an assignment to count inside inner, it treats count as a local variable in that function. Then the right-hand side tries to read the local variable before it has a value.
Use nonlocal For Rebinding
The fix is to tell Python that the name lives in the enclosing function scope.
This prints:
nonlocal count means assignments to count inside inner should update the variable from the nearest enclosing function scope that already defines count.
nonlocal Is Not global
nonlocal only targets enclosing function scopes. It does not reach module-level names. global is the keyword for rebinding a module-level variable.
This prints 25 and then 10. The inner function changed the variable in outer, not the module-level variable.
That distinction matters because global is often overused when nonlocal is the correct, narrower tool.
The Enclosing Variable Must Already Exist
nonlocal cannot create a brand-new name in the outer scope. The name must already be bound in an enclosing function.
This is invalid:
Python rejects it because there is no enclosing count to rebind. You must define the name first in the outer function.
Mutable Objects Are A Different Case
If you are not rebinding the outer name, you may not need nonlocal at all. Mutating a mutable object works because the name itself is not reassigned.
This works without nonlocal because items.append(...) mutates the list object. The variable items still points to the same list.
That difference is important:
- rebinding a name usually needs
nonlocal - mutating the object behind the name usually does not
A Common Closure Pattern
One clean use of nonlocal is building stateful functions.
This is a genuine closure. The returned function keeps access to value even after make_counter has finished executing.
For simple state, this is fine. If the behavior grows more complex, a class may become easier to read and test.
Older Python And Workarounds
In Python 2, nonlocal does not exist. Older code sometimes worked around that with a mutable container.
This works because the list is mutated, not rebound. In modern Python 3 code, nonlocal is usually clearer and should be preferred when the intent is rebinding an enclosing variable.
Common Pitfalls
- Forgetting that assignment inside the inner function creates a local binding by default.
- Using
globalwhen the real target is the enclosing function scope. - Declaring
nonlocalfor a name that does not exist in any enclosing function. - Assuming mutation and rebinding are the same thing.
- Using closure state when a small class would make the design easier to understand.
Summary
- Yes, Python can modify a variable from an enclosing non-global scope.
- In Python 3, use
nonlocalfor rebinding that variable. - '
nonlocaltargets enclosing function scope, whileglobaltargets module scope.' - Mutating a mutable outer object often works without
nonlocal. - If the shared state becomes complex, consider a class instead of nested functions.

