Bird
Raised Fist0
Pythonprogramming~15 mins

Nonlocal keyword in Python - Deep Dive

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Overview - Nonlocal keyword
What is it?
The nonlocal keyword in Python lets you work with variables inside nested functions by referring to variables in the nearest enclosing scope that is not global. It allows a function inside another function to modify a variable defined in the outer function. Without nonlocal, inner functions can only read but not change those outer variables. This keyword helps manage variable scope clearly and safely in nested functions.
Why it matters
Without the nonlocal keyword, you cannot change variables in an outer function from inside an inner function, which limits how you write nested functions that share state. This makes it harder to write clean, organized code that uses closures or nested helpers. Nonlocal solves this by giving a clear way to update outer variables, making your code more flexible and easier to understand. Without it, you might resort to confusing workarounds or global variables, which can cause bugs and messy code.
Where it fits
Before learning nonlocal, you should understand how variable scope works in Python, especially local and global scopes. You should also know about nested functions and closures. After mastering nonlocal, you can explore advanced function concepts like decorators, generators, and context managers that often use nested functions and scope manipulation.
Mental Model
Core Idea
Nonlocal lets an inner function change a variable in its nearest outer function, bridging scopes without using globals.
Think of it like...
Imagine a set of nested boxes, one inside another. Nonlocal is like a note you pass from the smallest box to the next bigger box, telling it to change something inside itself, without opening the biggest box (global).
Outer function scope
┌─────────────────────┐
│  variable x = 10    │
│  Inner function     │
│  ┌───────────────┐  │
│  │ nonlocal x    │  │
│  │ x = 20        │  │
│  └───────────────┘  │
└─────────────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding variable scopes
🤔
Concept: Learn how Python variables exist in different places called scopes: local, enclosing, global, and built-in.
In Python, when you create a variable inside a function, it's local to that function. Variables outside functions are global. If you have a function inside another function, the inner one can see variables from the outer one but cannot change them directly without special keywords.
Result
You know where variables live and which parts of your code can see or change them.
Understanding scopes is the base for knowing why nonlocal is needed to change variables in outer functions.
2
FoundationNested functions and variable access
🤔
Concept: See how inner functions can read but not modify outer function variables by default.
Define a function inside another function. The inner function can print or use variables from the outer function, but if it tries to assign to them, Python treats that as a new local variable, not changing the outer one.
Result
Inner functions can read outer variables but cannot change them without errors or unexpected behavior.
Knowing this limitation sets the stage for why nonlocal exists.
3
IntermediateIntroducing the nonlocal keyword
🤔Before reading on: do you think inner functions can change outer variables without any special keyword? Commit to your answer.
Concept: Nonlocal tells Python that a variable belongs to the nearest outer function scope, allowing the inner function to modify it.
Use 'nonlocal varname' inside an inner function to tell Python to use the variable from the nearest enclosing function scope. Then assignments change that outer variable, not create a new local one.
Result
Inner functions can now update variables in their outer functions, enabling shared state.
Understanding nonlocal unlocks powerful ways to write nested functions that share and update data cleanly.
4
IntermediateNonlocal vs global keywords
🤔Before reading on: do you think nonlocal and global keywords do the same thing? Commit to your answer.
Concept: Nonlocal changes variables in the nearest outer function, while global changes variables at the module (top) level.
Global affects variables defined outside all functions, at the top level of the file. Nonlocal affects variables in the closest outer function. Using global inside nested functions changes global variables, not outer function variables.
Result
You can control exactly which variable scope you want to modify: outer function or global.
Knowing the difference prevents bugs where you accidentally change global variables instead of outer function variables.
5
IntermediateCommon use cases for nonlocal
🤔
Concept: See practical examples where nonlocal helps, like counters or accumulators inside nested functions.
Write a function that returns an inner function which counts how many times it was called. Use nonlocal to update the count variable in the outer function each time the inner function runs.
Result
You create closures that keep and update state across calls without globals or classes.
Understanding these patterns shows how nonlocal enables elegant stateful functions.
6
AdvancedNonlocal in closures and decorators
🤔Before reading on: do you think decorators often need nonlocal to work correctly? Commit to your answer.
Concept: Nonlocal is key in advanced patterns like decorators, where inner functions modify outer variables to track or change behavior.
Decorators wrap functions with inner functions. To keep track of data like call counts or flags, decorators use nonlocal to update variables in the outer wrapper function.
Result
You can write powerful decorators that maintain internal state cleanly.
Knowing how nonlocal works inside decorators helps you write and debug complex Python code.
7
ExpertLimitations and pitfalls of nonlocal
🤔Before reading on: do you think nonlocal can access variables beyond the nearest enclosing function? Commit to your answer.
Concept: Nonlocal only works with variables in the nearest enclosing function scope, not global or built-in scopes, and can cause confusion if overused.
If a variable is not found in the nearest outer function, using nonlocal causes an error. Also, overusing nonlocal can make code harder to read and debug because it breaks the usual local variable isolation.
Result
You learn when nonlocal will fail and why to use it carefully.
Understanding these limits helps avoid bugs and write clearer, maintainable code.
Under the Hood
Python keeps track of variable scopes in a chain called the scope chain. When an inner function runs and sees a nonlocal declaration, it looks up the variable in the nearest enclosing function's local variables. Assignments then update that variable in the outer function's frame, not create a new local variable. This is managed by Python's runtime environment and its handling of function frames and closures.
Why designed this way?
Nonlocal was introduced to solve the problem of modifying outer function variables without resorting to globals or complex workarounds. It keeps variable scope clear and controlled, avoiding accidental global changes. Earlier Python versions lacked this, making nested functions less flexible. The design balances simplicity and power by limiting nonlocal to the nearest enclosing function scope.
┌───────────────┐
│ Global Scope  │
└──────┬────────┘
       │
┌──────▼────────┐
│ Outer Function│
│  x = 10       │
│  ┌─────────┐  │
│  │ Inner   │  │
│  │ Function│  │
│  │ nonlocal│  │
│  │ x       │  │
│  └─────────┘  │
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does nonlocal let you modify global variables from inside nested functions? Commit to yes or no.
Common Belief:Nonlocal works like global and lets you change global variables from inner functions.
Tap to reveal reality
Reality:Nonlocal only affects variables in the nearest enclosing function scope, not global variables.
Why it matters:Confusing nonlocal with global can cause bugs where you think you changed a global variable but actually get an error or unexpected behavior.
Quick: Can nonlocal be used to create new variables in outer functions? Commit to yes or no.
Common Belief:Using nonlocal creates a new variable in the outer function if it doesn't exist.
Tap to reveal reality
Reality:Nonlocal requires the variable to already exist in the nearest outer function; otherwise, Python raises an error.
Why it matters:Trying to create variables with nonlocal causes runtime errors, confusing beginners.
Quick: Does nonlocal affect variables in all outer functions if nested multiple levels? Commit to yes or no.
Common Belief:Nonlocal can modify variables in any outer function, no matter how far away.
Tap to reveal reality
Reality:Nonlocal only modifies variables in the closest enclosing function scope, not beyond that.
Why it matters:Misunderstanding this leads to bugs when you expect changes in outer scopes that nonlocal cannot reach.
Quick: Is nonlocal always the best way to share state in nested functions? Commit to yes or no.
Common Belief:Nonlocal is always the best and safest way to share and modify state in nested functions.
Tap to reveal reality
Reality:Nonlocal can make code harder to read and debug if overused; sometimes using objects or passing parameters is clearer.
Why it matters:Overusing nonlocal can lead to confusing code and maintenance problems.
Expert Zone
1
Nonlocal only works with variables in function scopes, not with mutable objects unless you reassign the variable itself.
2
Using nonlocal can affect performance slightly because Python must look up variables in the enclosing scope chain at runtime.
3
In multi-threaded or asynchronous code, nonlocal variables can cause subtle bugs if shared state is not managed carefully.
When NOT to use
Avoid nonlocal when you can use function arguments, return values, or objects to manage state. For complex state sharing, classes or data structures are clearer and safer. Also, do not use nonlocal to modify global variables; use global instead or better design patterns.
Production Patterns
Nonlocal is commonly used in decorators to maintain state like call counts or flags. It's also used in closures for counters, accumulators, or memoization. Experienced developers use it sparingly to keep code clean and prefer explicit state management for complex cases.
Connections
Closures
Nonlocal enables closures to modify enclosed variables, making closures stateful.
Understanding nonlocal deepens your grasp of closures, which are functions remembering their environment.
Mutable vs Immutable Types
Nonlocal affects variable bindings, not the contents of mutable objects, highlighting the difference between rebinding and mutation.
Knowing this helps avoid confusion when modifying lists or dictionaries inside nested functions.
Lexical Scoping in Programming Languages
Nonlocal is a feature that enforces lexical scoping rules by allowing inner functions to access and modify outer scopes.
This connects Python's behavior to a fundamental concept in many programming languages, showing how scope rules shape code structure.
Common Pitfalls
#1Trying to assign to an outer variable without nonlocal causes a new local variable instead of changing the outer one.
Wrong approach:def outer(): x = 5 def inner(): x = 10 # This creates a new local x, does not change outer x inner() print(x) # Prints 5, not 10
Correct approach:def outer(): x = 5 def inner(): nonlocal x x = 10 # Changes outer x inner() print(x) # Prints 10
Root cause:Without nonlocal, Python treats assignment as creating a new local variable, not modifying the outer one.
#2Using nonlocal for a variable that does not exist in any outer function scope causes an error.
Wrong approach:def outer(): def inner(): nonlocal x # Error: no binding for nonlocal 'x' found x = 5 inner()
Correct approach:def outer(): x = 0 def inner(): nonlocal x x = 5 inner()
Root cause:Nonlocal requires the variable to exist in the nearest enclosing function scope.
#3Confusing nonlocal with global and trying to modify global variables with nonlocal.
Wrong approach:def outer(): def inner(): nonlocal x # Error if x is global, not in outer function x = 10 inner() x = 0 outer()
Correct approach:x = 0 def outer(): def inner(): global x x = 10 inner() outer()
Root cause:Nonlocal only works for variables in enclosing functions, not global variables.
Key Takeaways
The nonlocal keyword allows inner functions to modify variables in their nearest enclosing function scope, enabling shared state without globals.
Nonlocal is different from global; it only affects variables in outer functions, not at the module level.
Using nonlocal requires the variable to already exist in the outer function; otherwise, Python raises an error.
Nonlocal is essential for writing closures and decorators that maintain internal state cleanly and safely.
Overusing nonlocal can make code harder to read and debug, so use it carefully and prefer clearer state management when possible.

Practice

(1/5)
1. What does the nonlocal keyword do in Python?
easy
A. Declares a variable as global across all modules.
B. Allows an inner function to modify a variable from its outer function.
C. Creates a new local variable inside the inner function.
D. Prevents any changes to variables in the outer function.

Solution

  1. Step 1: Understand variable scopes

    Variables inside a function are local by default, and inner functions cannot change outer variables unless specified.
  2. Step 2: Role of nonlocal

    The nonlocal keyword allows the inner function to access and modify variables from the nearest enclosing function scope.
  3. Final Answer:

    Allows an inner function to modify a variable from its outer function. -> Option B
  4. Quick Check:

    nonlocal changes outer function variable = A [OK]
Hint: Nonlocal lets inner functions change outer variables [OK]
Common Mistakes:
  • Confusing nonlocal with global keyword
  • Thinking nonlocal creates new variables
  • Assuming nonlocal works outside functions
2. Which of the following is the correct syntax to use nonlocal inside a nested function?
easy
A. local variable_name
B. global variable_name
C. outer variable_name
D. nonlocal variable_name

Solution

  1. Step 1: Recall the syntax for nonlocal

    The keyword nonlocal is followed by the variable name to indicate it refers to an outer function's variable.
  2. Step 2: Compare options

    Only nonlocal variable_name uses the correct keyword and syntax: nonlocal variable_name.
  3. Final Answer:

    nonlocal variable_name -> Option D
  4. Quick Check:

    Correct nonlocal syntax = C [OK]
Hint: Use 'nonlocal' followed by variable name inside inner function [OK]
Common Mistakes:
  • Using 'global' instead of 'nonlocal'
  • Writing 'local' or 'outer' which are invalid keywords
  • Forgetting to write variable name after nonlocal
3. What will be the output of the following code?
def outer():
    x = 5
    def inner():
        nonlocal x
        x = 10
    inner()
    return x
print(outer())
medium
A. 10
B. None
C. Error: no binding for nonlocal 'x'
D. 5

Solution

  1. Step 1: Trace variable assignment

    Variable x is set to 5 in outer(). The inner function declares nonlocal x and sets x = 10.
  2. Step 2: Effect of nonlocal on x

    The nonlocal keyword allows inner() to modify x in outer(). So after calling inner(), x becomes 10.
  3. Final Answer:

    10 -> Option A
  4. Quick Check:

    nonlocal changes outer x to 10 = D [OK]
Hint: nonlocal lets inner change outer variable value [OK]
Common Mistakes:
  • Thinking x remains 5 because inner is separate
  • Expecting a syntax error for nonlocal usage
  • Assuming inner creates a new local x
4. Find the error in this code snippet:
def counter():
    count = 0
    def increment():
        count = count + 1
        return count
    return increment()
print(counter())
medium
A. increment() should not return count
B. count should be global, not local
C. Missing 'nonlocal count' inside increment()
D. No error, code runs fine

Solution

  1. Step 1: Identify variable scope issue

    Inside increment(), count = count + 1 tries to read and write count. Without nonlocal, Python treats count as local, but it is used before assignment.
  2. Step 2: Fix with nonlocal

    Adding nonlocal count tells Python to use the count from counter(), allowing modification.
  3. Final Answer:

    Missing 'nonlocal count' inside increment() -> Option C
  4. Quick Check:

    Modify outer variable needs nonlocal = A [OK]
Hint: Add nonlocal before modifying outer variable inside inner function [OK]
Common Mistakes:
  • Using global instead of nonlocal
  • Ignoring variable scope causing UnboundLocalError
  • Returning count without incrementing properly
5. Consider this code:
def make_accumulator():
    total = 0
    def add(value):
        nonlocal total
        total += value
        return total
    return add
acc = make_accumulator()
print(acc(5))
print(acc(3))
print(acc(-2))

What is the output of this code?
hard
A. 5\n8\n6
B. 5\n3\n-2
C. 0\n5\n8
D. Error: nonlocal used incorrectly

Solution

  1. Step 1: Understand closure with nonlocal

    The function make_accumulator() returns add, which remembers total. The nonlocal total lets add update total each call.
  2. Step 2: Trace calls to acc

    First call: total=0+5=5, prints 5.
    Second call: total=5+3=8, prints 8.
    Third call: total=8+(-2)=6, prints 6.
  3. Final Answer:

    5 8 6 -> Option A
  4. Quick Check:

    Accumulator sums values using nonlocal total = B [OK]
Hint: nonlocal keeps state in nested function closures [OK]
Common Mistakes:
  • Expecting total to reset each call
  • Confusing nonlocal with global
  • Thinking output is separate values, not cumulative