Python Nonlocal Keyword in Nested Functions
The nonlocal keyword in Python allows inner functions to
modify variables defined in an enclosing outer scope without converting
those variables into globals. This article explains the exact purpose of
nonlocal, how it resolves variable scoping conflicts inside
nested functions, how it differs from the global keyword,
and how to use it properly with clear code examples.
Understanding the Scope Problem
Python resolves variable names using the LEGB rule, which stands for Local, Enclosing, Global, and Built-in scopes. When working with nested functions, an inner function can freely read variables defined in the outer function. However, the moment you attempt to reassign that variable inside the inner function, Python automatically treats it as a new local variable unless told otherwise.
Consider this example without nonlocal:
def outer():
count = 0
def inner():
count += 1 # UnboundLocalError: local variable 'count' referenced before assignment
return count
return innerIn the code above, assigning to count creates a new
local variable named count inside inner().
Because the assignment expression references count before
assigning to it, Python raises an UnboundLocalError.
How the nonlocal
Keyword Works
The nonlocal keyword explicitly declares that a variable
refers to a previously bound variable in the nearest enclosing scope,
excluding the global scope. This allows you to modify the outer
variable's value directly.
def make_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
my_counter = make_counter()
print(my_counter()) # Outputs: 1
print(my_counter()) # Outputs: 2
print(my_counter()) # Outputs: 3By placing nonlocal count inside counter(),
Python points all operations on count directly to the
count variable declared in make_counter().
This pattern is widely used in closures and stateful function decorators
to preserve state across multiple function calls without using class
instances or global state.
nonlocal vs.
global
While both keywords allow modification of variables defined outside the current function, they target entirely different scopes:
globalbinds a variable to the module-level (top-level) scope. It cannot target intermediate functions.nonlocalbinds a variable to the nearest enclosing function scope. It specifically excludes both the local scope of the current function and the global/module scope.
Important Restrictions
- Must already exist: A
nonlocalvariable must already be defined in an enclosing function. If the variable is not found in an outer function scope, Python raises aSyntaxError: no binding for nonlocal '<variable>' found. - Cannot be global: If you try to use
nonlocalon a variable that only exists at the module level, Python will raise aSyntaxError. You must useglobalfor module-level variables.