Using nonlocal in Nested Functions
The nonlocal keyword allows a nested (inner) function to modify a variable from its enclosing (outer) function’s scope. While not used as frequently as global, it is very useful in specific data science scenarios such as creating counters, accumulators, or maintaining state within nested helper functions.
TL;DR — When to Use nonlocal
- Use
nonlocalwhen a nested function needs to modify a variable defined in the enclosing function - Do not use it to modify global variables (use
globalfor that) - Most common use cases: counters, accumulators, and stateful nested functions
1. Basic Example of nonlocal
def process_batch(transactions):
total_revenue = 0.0 # Variable in enclosing scope
def add_transaction(amount: float):
nonlocal total_revenue # Allows inner function to modify outer variable
total_revenue += amount
for tx in transactions:
add_transaction(tx["amount"])
return total_revenue
# Usage
batch = [{"amount": 1250.75}, {"amount": 890.50}, {"amount": 2340.00}]
revenue = process_batch(batch)
print(f"Total revenue: {revenue}")
2. Real-World Data Science Example
def calculate_running_metrics(df):
"""Calculate running statistics using nested function with nonlocal."""
running_sum = 0.0
running_count = 0
def update_running_stats(amount: float):
nonlocal running_sum, running_count
running_sum += amount
running_count += 1
return running_sum / running_count if running_count > 0 else 0
df = df.copy()
df["running_avg"] = df["amount"].apply(update_running_stats)
return df
3. Best Practices in 2026
- Use
nonlocalonly when you need the inner function to modify a variable from the outer scope - Prefer returning values instead of using
nonlocalwhen possible (more functional style) - Limit the use of
nonlocalto small, well-contained nested functions - Document clearly when a nested function modifies outer variables using
nonlocal - Be cautious — overuse of
nonlocalcan make code harder to understand and debug
What nonlocal Does
nonlocal tells Python that a name in a nested function refers to a variable in the nearest enclosing function, not a new local one. Without it, assigning to that name inside the inner function creates a separate local variable.
It is most useful for small stateful closures such as counters or running totals. For anything with several pieces of state, a class is usually clearer.
Worked Example: A Running Total
A closure keeps a running total across calls using nonlocal.
def make_accumulator():
total = 0.0
def add(value: float) -> float:
nonlocal total
total += value
return total
return add
acc = make_accumulator()
for v in [10.0, 5.5, 4.5]:
print(acc(v))
other = make_accumulator()
print(other(1.0))
Each call adds to the same total, giving 10.0, 15.5 and 20.0. A second accumulator starts from zero, because every call to the factory creates a new enclosing scope.
Practical Tips
The difference between global, nonlocal and local names is easy to test with small experiments. Try removing the nonlocal line in the example: Python will raise an UnboundLocalError on the first call, because total += value tries to read a local name before assigning it.
In data pipelines, nonlocal closures can count processed records or keep the last seen value in a stream. Once you need to reset, inspect or serialise the state, rewrite the closure as a small class with clear attributes.
Remember that nonlocal only works for names that already exist in an enclosing function. It cannot create a new variable, and it cannot reach module-level names; those need the global keyword instead. Keeping the state small makes such closures easy to reason about.
Common Mistakes
- Using global when nonlocal is meant.
- Forgetting nonlocal and getting an UnboundLocalError.
- Keeping lots of state in closures instead of a class.
- Using nonlocal at module level, which is a syntax error.
Quick Summary
- nonlocal targets the enclosing function scope.
- It allows assignment to outer variables.
- Good for counters and running totals.
- Use a class for complex state.
Conclusion
The nonlocal keyword is a specialized tool that allows nested functions to modify variables from their enclosing scope. In data science, it is most useful for creating accumulators, counters, or maintaining state within a parent function. However, in most cases, returning values explicitly is cleaner and more maintainable than relying on nonlocal.
Next steps:
- Review your current code and identify any nested functions that modify outer variables. Consider whether using
nonlocalis the best approach or if returning values would be cleaner.