nonlocal

Updated March 16, 2026 · Keywords
keyword scope variable nested-function

The nonlocal keyword lets you declare that a variable inside a nested function refers to a variable in an enclosing function scope, not a local variable. This allows you to modify variables from an outer (but non-global) function.

Syntax

nonlocal variable_name

You can declare multiple nonlocal variables by separating them with commas:

nonlocal x, y, z

How It Works

When you define a function inside another function, the inner function can read variables from the outer function by default. However, to modify those variables, you must declare them as nonlocal:

# Without nonlocal - creates a new local variable
def outer():
    x = 10
    
    def inner():
        x = 20  # This creates a NEW local variable
        print(x)  # 20
    
    inner()
    print(x)  # 10 (outer x unchanged)

# With nonlocal - modifies the outer function variable
def outer():
    x = 10
    
    def inner():
        nonlocal x
        x = 20  # This modifies the outer x
        print(x)  # 20
    
    inner()
    print(x)  # 20 (outer x modified)

outer()
# Output:
# 20
# 20

Common Use Cases

Closures that modify captured variables

def create_counter():
    count = 0
    
    def increment():
        nonlocal count
        count += 1
        return count
    
    return increment

counter = create_counter()
print(counter())  # 1
print(counter())  # 2
print(counter())  # 3

Factory functions

def make_multiplier(factor):
    def multiplier(n):
        nonlocal factor
        return n * factor
    return multiplier

double = make_multiplier(2)
print(double(5))  # 10

triple = make_multiplier(3)
print(triple(5))  # 15

State in nested functions

def player(name):
    score = 0
    
    def win(points):
        nonlocal score
        score += points
        return f"{name}: {score}"
    
    return win

game = player("Alice")
print(game(10))  # Alice: 10
print(game(5))   # Alice: 15

nonlocal vs global

Aspectnonlocalglobal
ScopeEnclosing functionModule level
Requires nested functionYesNo
Common useClosuresModule configuration
x = "global"

def outer():
    x = "outer"
    
    def inner():
        global x      # Modifies module-level x
        x = "changed globally"
    
    inner()
    print(x)  # "outer" (unchanged)

def outer2():
    x = "outer"
    
    def inner():
        nonlocal x  # Modifies outer function x
        x = "changed locally"
    
    inner()
    print(x)  # "changed locally"

outer()
outer2()
# Output:
# outer
# changed locally

Best Practice

While nonlocal is useful for closures, consider these alternatives:

Using a mutable container

def create_counter():
    state = [0]  # Mutable list
    
    def increment():
        state[0] += 1
        return state[0]
    
    return increment

Using classes

class Counter:
    def __init__(self):
        self.count = 0
    
    def increment(self):
        self.count += 1
        return self.count

Gotchas

Forgetting nonlocal

def outer():
    value = 10
    
    def inner():
        value += 1  # UnboundLocalError!
    
    inner()

This raises UnboundLocalError because Python sees an assignment and treats value as local. Use nonlocal value.

Trying to use nonlocal in the same scope

value = 10

def same_scope():
    nonlocal value  # SyntaxError!

nonlocal only works inside nested functions, not at the same level as the variable.

Shadowing global variables

x = 1

def outer():
    x = 2
    
    def inner():
        nonlocal x
        x = 3
    
    inner()
    print(x)  # 3

outer()
print(x)  # 1 (global x unchanged)

See Also