The nonlocal Keyword in Python 2026

Writing Functions Mar 16, 2026

The nonlocal Keyword in Python 2026

The nonlocal keyword allows an inner (nested) function to modify a variable from its immediately enclosing (outer) function’s scope. It is the nested-function counterpart to the global keyword and is essential when working with closures and factory functions.

TL;DR — Key Takeaways 2026

  • nonlocal lets inner functions modify variables in the enclosing function scope
  • It only works inside nested functions (not at module level)
  • Commonly used in closures, counters, and stateful inner functions
  • Prefer returning values or using classes when possible

1. Basic Usage of nonlocal


def outer():
    count = 0
    
    def inner():
        nonlocal count        # Allows modification of outer's 'count'
        count += 1
        return count
    
    return inner

counter = outer()

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

2. Practical Example – Stateful Closure


def make_accumulator(initial: int = 0):
    total = initial
    
    def add(value: int) -> int:
        nonlocal total
        total += value
        return total
    
    return add

acc = make_accumulator(100)

print(acc(10))    # 110
print(acc(25))    # 135
print(acc(-5))    # 130

3. Best Practices in 2026

  • Use nonlocal only when you need to modify enclosing scope variables
  • Keep the outer function small and focused when using nonlocal
  • Document the use of nonlocal clearly
  • Consider classes or returning a mutable object when state becomes complex
  • Combine with type hints for better readability

What nonlocal Changes

nonlocal tells Python that a name in a nested function refers to a variable in the nearest enclosing function, not a new local variable and not a global. It is needed only when the inner function rebinds the name, for example with = or +=.

Without nonlocal, an assignment inside the inner function creates a local name, and a read before it fails with UnboundLocalError. Mutating an outer list or dictionary does not need nonlocal, because the name itself is not rebound.

nonlocal can only refer to function scopes. Using it for a module-level name raises a SyntaxError, because module names are global, not enclosing.

The keyword is most useful for small closures that keep a running value, such as a counter or a running total.

Worked Example: Rebinding Versus Mutating

We compare a counter that needs nonlocal with a log list that does not.

def make_tracker():
    count = 0
    log = []

    def track(event):
        nonlocal count          # rebinding needs nonlocal
        count += 1
        log.append(event)       # mutation does not
        return count, list(log)

    return track

track = make_tracker()
print(track("start"))
print(track("click"))

try:
    exec("x = 1\ndef f():\n    nonlocal x\n")
except SyntaxError as e:
    print("SyntaxError:", e.msg)

The tracker returns (1, ['start']) and then (2, ['start', 'click']). Only count needed nonlocal. Trying to use nonlocal for a module-level name raises a SyntaxError saying no binding for nonlocal 'x' found.

Practical Tips

If a closure needs several pieces of changing state, a small class with attributes is often clearer than several nonlocal names. The class also makes the state visible for debugging.

Write a short test that calls the closure several times and checks the result after each call. Bugs with nonlocal usually show up only on the second call, when the old value is used.

Keep the enclosing variable's name distinct from any global name, so readers do not confuse the two scopes.

Remember that each call of the factory creates a separate state, which makes closures easy to reset by simply creating a new one.

In Python 3, nonlocal replaces older tricks such as storing a counter in a one-element list. Use the keyword in new code because it states the intent directly.

A quick test calling the closure twice confirms that the value persists.

Common Mistakes

  • Using nonlocal when you only mutate a list or dict.
  • Using nonlocal for module variables instead of global.
  • Chaining many nonlocal names, which hides state.
  • Forgetting that each factory call creates a fresh variable.

Quick Summary

  • nonlocal rebinds a variable in an enclosing function.
  • Mutation needs no declaration.
  • It cannot refer to module names.
  • Ideal for small counters and totals.

Conclusion

The nonlocal keyword is a clean and powerful tool for working with nested functions and closures. In 2026, it is commonly used to create simple stateful functions and factories. However, for more complex state management, classes or returning objects are often preferred for better maintainability.

Next steps:

  • Review your nested functions and use nonlocal where you need to modify enclosing variables

Related Tutorials

Share:
Last updated: March 2026
Built-in Functions in Python 2026 str() in Python 2026: String Conversion + Modern Formatting & Best Practices memoryview with JAX in Python 2026: Zero-Copy NumPy → JAX Array Interop + Efficient ML Examples memoryview with TensorFlow in Python 2026: Zero-Copy NumPy → Tensor Interop + GPU Pinning & ML Examples memoryview with TensorFlow in Python 2026: Zero-Copy NumPy → Tensor Interop + ML Examples memoryview with NumPy & PyTorch in Python 2026: Zero-Copy Views, Efficient Slicing & ML Interop Examples memoryview with NumPy in Python 2026: Zero-Copy Views, Efficient Slicing & Real ML Examples memoryview() in Python 2026: Zero-Copy Magic for Large Binary Data + Real Examples import() in Python 2026: How It Works, Security Risks & Modern Alternatives (importlib) zip() in Python 2026: How to Use It, strict=True Behavior & Real-World Examples vars() in Python 2026: Accessing Object Namespace + Modern Introspection Patterns type() in Python 2026: Dynamic Type Inspection & Object Creation + Modern Patterns tuple() in Python 2026: Immutable Sequences + Modern Patterns & Best Practices super() in Python 2026: Method Resolution & Modern Inheritance Patterns sum() in Python 2026: Summing Iterables + Modern Numeric Patterns & Best Practices staticmethod() in Python 2026: Static Methods, Utility Functions & Modern Best Practices sorted() in Python 2026: Sorting Iterables + Modern Patterns & Best Practices slice() in Python 2026: Creating Slice Objects + Modern Patterns & Best Practices setattr() in Python 2026: Dynamic Attribute Setting + Modern Patterns & Safety set() in Python 2026: Mutable Sets Creation + Modern Patterns & Best Practices