Nonlocal Keyword in Nested Functions

🏷️ Functions / Variable Scope

🔍 Context Introduction

When you create functions inside other functions (nested functions), you might want to modify variables from the outer function. Python's scoping rules normally prevent this, but the nonlocal keyword gives you a way to work with variables from enclosing (but not global) scopes. This is especially useful when building closures or maintaining state across multiple function calls.


⚙️ What is the Nonlocal Keyword?

  • nonlocal allows a nested function to assign values to variables defined in its enclosing function
  • It works for variables that are not global and not local to the current function
  • Without nonlocal, assigning to a variable inside a nested function creates a new local variable instead
  • The keyword must be used before you assign to the variable in the nested function

🛠️ Basic Syntax and Usage

Declaring a nonlocal variable inside a nested function:

  • Write nonlocal variable_name as the first line inside the nested function
  • Then you can assign new values to that variable
  • The change affects the variable in the outer function

Simple example structure:

  • Outer function defines a variable called counter
  • Inner function uses nonlocal counter to modify it
  • Each call to the inner function updates the outer variable

📊 Comparison: With and Without Nonlocal

Scenario Behavior Variable Affected
Without nonlocal Creates a new local variable inside the nested function Only the inner function's local scope
With nonlocal Modifies the variable from the enclosing function The outer function's scope
With global Modifies a module-level variable The global scope

🕵️ Common Use Cases

Tracking state across multiple calls:

  • Use a counter variable in the outer function
  • Increment it inside the nested function using nonlocal
  • Each call remembers the previous count

Building configuration helpers:

  • Outer function stores a configuration dictionary
  • Nested functions modify specific keys using nonlocal
  • Changes persist for the lifetime of the outer function

Implementing simple decorators:

  • Outer function holds a reference count or cache
  • Inner function updates these values with nonlocal
  • Maintains state between decorated function calls

💡 Important Rules to Remember

  • nonlocal only works with variables from enclosing function scopes, not global scope
  • The variable must already exist in the enclosing scope before you use nonlocal
  • You cannot use nonlocal for variables defined in the same function (those are local)
  • You can use nonlocal for multiple variables in one statement: nonlocal x, y, z
  • Python searches outward through enclosing scopes until it finds the variable

🔄 Nested Functions with Multiple Levels

  • If you have three levels of nested functions, nonlocal can reach variables from any enclosing function
  • Python starts from the immediate outer function and works outward
  • The variable must exist in at least one enclosing scope (not global)

⚠️ Common Mistakes to Avoid

  • Forgetting to declare nonlocal before assigning to the variable
  • Trying to use nonlocal for a variable that doesn't exist in any enclosing scope
  • Confusing nonlocal with global (they work at different levels)
  • Using nonlocal for variables that are only read (not assigned) — it's unnecessary

🎯 Practical Example Walkthrough

Scenario: Building a simple counter function

  • Outer function make_counter defines a variable count = 0
  • Inner function increment uses nonlocal count to modify it
  • Each call to increment increases count by 1
  • The outer function returns the inner function

What happens step by step:

  1. Call make_counter() — creates count = 0 and returns the inner function
  2. Call the returned function — nonlocal count allows incrementing
  3. The count variable persists between calls because it's in the enclosing scope

📝 Key Takeaways

  • nonlocal bridges the gap between local and global variable scopes
  • It enables nested functions to modify state from their enclosing functions
  • Essential for creating closures and maintaining persistent state
  • Always declare nonlocal before any assignment to the variable
  • Use it when you need to update outer function variables from within nested functions

The nonlocal keyword allows a nested function to modify a variable from its enclosing function's scope.


🔧 Example 1: Basic variable access without nonlocal

This example shows that a nested function can read, but not modify, a variable from the enclosing function.

def outer():
    value = 10

    def inner():
        print(value)

    inner()

outer()

📤 Output: 10


🔧 Example 2: Trying to modify without nonlocal

This example shows what happens when you try to assign to a variable from the enclosing scope without using nonlocal.

def outer():
    value = 10

    def inner():
        value = 20
        print("Inside inner:", value)

    inner()
    print("Inside outer:", value)

outer()

📤 Output: Inside inner: 20
Inside outer: 10


🔧 Example 3: Using nonlocal to modify the enclosing variable

This example demonstrates how nonlocal allows a nested function to change a variable from its enclosing function.

def outer():
    value = 10

    def inner():
        nonlocal value
        value = 20
        print("Inside inner:", value)

    inner()
    print("Inside outer:", value)

outer()

📤 Output: Inside inner: 20
Inside outer: 20


🔧 Example 4: Multiple levels of nesting with nonlocal

This example shows how nonlocal works across two levels of nested functions to modify a variable from the outermost function.

def outer():
    count = 0

    def middle():
        nonlocal count

        def inner():
            nonlocal count
            count = count + 1

        inner()

    middle()
    print("Final count:", count)

outer()

📤 Output: Final count: 1


🔧 Example 5: Practical counter using nonlocal

This example shows a practical use of nonlocal to create a counter that remembers its state between calls.

def make_counter():
    count = 0

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

    return increment

counter = make_counter()
print(counter())
print(counter())
print(counter())

📤 Output: 1
2
3


📊 Comparison Table: local vs nonlocal vs global

Scope Keyword Where variable is found Can modify?
Local (none) Inside current function Yes
Enclosing nonlocal In a function that contains this one Yes
Global global At the top level of the module Yes

🔍 Context Introduction

When you create functions inside other functions (nested functions), you might want to modify variables from the outer function. Python's scoping rules normally prevent this, but the nonlocal keyword gives you a way to work with variables from enclosing (but not global) scopes. This is especially useful when building closures or maintaining state across multiple function calls.


⚙️ What is the Nonlocal Keyword?

  • nonlocal allows a nested function to assign values to variables defined in its enclosing function
  • It works for variables that are not global and not local to the current function
  • Without nonlocal, assigning to a variable inside a nested function creates a new local variable instead
  • The keyword must be used before you assign to the variable in the nested function

🛠️ Basic Syntax and Usage

Declaring a nonlocal variable inside a nested function:

  • Write nonlocal variable_name as the first line inside the nested function
  • Then you can assign new values to that variable
  • The change affects the variable in the outer function

Simple example structure:

  • Outer function defines a variable called counter
  • Inner function uses nonlocal counter to modify it
  • Each call to the inner function updates the outer variable

📊 Comparison: With and Without Nonlocal

Scenario Behavior Variable Affected
Without nonlocal Creates a new local variable inside the nested function Only the inner function's local scope
With nonlocal Modifies the variable from the enclosing function The outer function's scope
With global Modifies a module-level variable The global scope

🕵️ Common Use Cases

Tracking state across multiple calls:

  • Use a counter variable in the outer function
  • Increment it inside the nested function using nonlocal
  • Each call remembers the previous count

Building configuration helpers:

  • Outer function stores a configuration dictionary
  • Nested functions modify specific keys using nonlocal
  • Changes persist for the lifetime of the outer function

Implementing simple decorators:

  • Outer function holds a reference count or cache
  • Inner function updates these values with nonlocal
  • Maintains state between decorated function calls

💡 Important Rules to Remember

  • nonlocal only works with variables from enclosing function scopes, not global scope
  • The variable must already exist in the enclosing scope before you use nonlocal
  • You cannot use nonlocal for variables defined in the same function (those are local)
  • You can use nonlocal for multiple variables in one statement: nonlocal x, y, z
  • Python searches outward through enclosing scopes until it finds the variable

🔄 Nested Functions with Multiple Levels

  • If you have three levels of nested functions, nonlocal can reach variables from any enclosing function
  • Python starts from the immediate outer function and works outward
  • The variable must exist in at least one enclosing scope (not global)

⚠️ Common Mistakes to Avoid

  • Forgetting to declare nonlocal before assigning to the variable
  • Trying to use nonlocal for a variable that doesn't exist in any enclosing scope
  • Confusing nonlocal with global (they work at different levels)
  • Using nonlocal for variables that are only read (not assigned) — it's unnecessary

🎯 Practical Example Walkthrough

Scenario: Building a simple counter function

  • Outer function make_counter defines a variable count = 0
  • Inner function increment uses nonlocal count to modify it
  • Each call to increment increases count by 1
  • The outer function returns the inner function

What happens step by step:

  1. Call make_counter() — creates count = 0 and returns the inner function
  2. Call the returned function — nonlocal count allows incrementing
  3. The count variable persists between calls because it's in the enclosing scope

📝 Key Takeaways

  • nonlocal bridges the gap between local and global variable scopes
  • It enables nested functions to modify state from their enclosing functions
  • Essential for creating closures and maintaining persistent state
  • Always declare nonlocal before any assignment to the variable
  • Use it when you need to update outer function variables from within nested functions

Interactive Views

You are currently in 📚 All-in-One mode. Use the tabs at the top to switch to 📖 Theory Only or 💻 Code Only views.

The nonlocal keyword allows a nested function to modify a variable from its enclosing function's scope.


🔧 Example 1: Basic variable access without nonlocal

This example shows that a nested function can read, but not modify, a variable from the enclosing function.

def outer():
    value = 10

    def inner():
        print(value)

    inner()

outer()

📤 Output: 10


🔧 Example 2: Trying to modify without nonlocal

This example shows what happens when you try to assign to a variable from the enclosing scope without using nonlocal.

def outer():
    value = 10

    def inner():
        value = 20
        print("Inside inner:", value)

    inner()
    print("Inside outer:", value)

outer()

📤 Output: Inside inner: 20
Inside outer: 10


🔧 Example 3: Using nonlocal to modify the enclosing variable

This example demonstrates how nonlocal allows a nested function to change a variable from its enclosing function.

def outer():
    value = 10

    def inner():
        nonlocal value
        value = 20
        print("Inside inner:", value)

    inner()
    print("Inside outer:", value)

outer()

📤 Output: Inside inner: 20
Inside outer: 20


🔧 Example 4: Multiple levels of nesting with nonlocal

This example shows how nonlocal works across two levels of nested functions to modify a variable from the outermost function.

def outer():
    count = 0

    def middle():
        nonlocal count

        def inner():
            nonlocal count
            count = count + 1

        inner()

    middle()
    print("Final count:", count)

outer()

📤 Output: Final count: 1


🔧 Example 5: Practical counter using nonlocal

This example shows a practical use of nonlocal to create a counter that remembers its state between calls.

def make_counter():
    count = 0

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

    return increment

counter = make_counter()
print(counter())
print(counter())
print(counter())

📤 Output: 1
2
3


📊 Comparison Table: local vs nonlocal vs global

Scope Keyword Where variable is found Can modify?
Local (none) Inside current function Yes
Enclosing nonlocal In a function that contains this one Yes
Global global At the top level of the module Yes