Table of contents
1.
Introduction
2.
Python nonlocal Keyword Example
3.
What is the nonlocal Keyword in Python?
4.
Advantages of nonlocal
5.
Disadvantages of nonlocal
6.
Nonlocal in Nested Functions
7.
Understanding Variable Scope in Python
7.1.
Local Scope
7.2.
Global Scope:
7.3.
Nonlocal Scope
7.4.
Expanding the Scope: Python Nonlocal in Larger Scripts
8.
Examples
8.1.
Example 1: Modifying Outer Variable in a Nested Function
8.2.
Example 2: Using nonlocal to Track State Across Function Calls
9.
Exploring Alternatives to Python Nonlocal
10.
Troubleshooting Python Nonlocal: Common Issues and Solutions
11.
Frequently Asked Questions
11.1.
What happens if I don’t use nonlocal inside a nested function?
11.2.
Can I use nonlocal with global variables?
11.3.
Is nonlocal always necessary for nested functions?
12.
Conclusion
Last Updated: Dec 28, 2024
Easy

The nonlocal Keyword in Python

Author Gaurav Gandhi
0 upvote

Introduction

The nonlocal keyword in Python is a unique feature that allows you to work with variables in an outer but non-global scope, such as in a nested function. It is useful when you need to modify a variable in a nested function that is not in the global scope or the local function scope. 

The nonlocal Keyword in Python

This article will explain the nonlocal keyword in detail, showing how and why it's used, its advantages and disadvantages, and providing examples to help you understand it better.

Python nonlocal Keyword Example

Let’s start by understanding the basic example where the nonlocal keyword is used.

def outer_function():
    x = 10    
    def inner_function():
        nonlocal x
        x = 20
        print("Value of x inside inner_function:", x)    
    inner_function()
    print("Value of x after calling inner_function:", x)

outer_function()
You can also try this code with Online Python Compiler
Run Code


Output:

Value of x inside inner_function: 20
Value of x after calling inner_function: 20


In this example, the variable x is defined in the outer_function scope. The inner function modifies the value of x using the nonlocal keyword. Without the nonlocal keyword, the inner function would have created its own local variable x, leaving the x in the outer function unchanged.

What is the nonlocal Keyword in Python?

The nonlocal keyword is used to declare variables in a nested function scope, allowing you to modify the value of variables in the enclosing (non-global) scope. It works similarly to the global keyword, but instead of referring to global variables, it targets variables in the nearest enclosing function scope.

By using nonlocal, you can avoid creating new local variables in a nested function and instead update the variable defined in the outer function. This is helpful when you want to modify the value of variables within a function without changing them globally.

Advantages of nonlocal

  1. Access to Outer Scope Variables: The nonlocal keyword enables a function to modify variables from an enclosing function that aren't in the global scope. This is useful for maintaining state across multiple function calls without using global variables.
     
  2. Improved Code Readability: By using nonlocal, you avoid the need to pass variables explicitly between functions, reducing the number of arguments passed and making your code cleaner and easier to read.
     
  3. No Need for Global Variables: When you want to modify a variable in a nested function, using nonlocal is more efficient than relying on global variables, which can be harder to manage and lead to bugs in larger programs.
     
  4. Control Over Variable Scope: The nonlocal keyword helps you control the scope of variables, allowing you to maintain a more predictable flow in your program by making sure certain variables stay confined to a specific scope, rather than affecting the entire program.

Disadvantages of nonlocal

  1. Can Lead to Confusion: While nonlocal can make your code more concise, it can also make it harder to understand, especially for beginner programmers. It can be difficult to track changes to variables when they are modified in different scopes.
     
  2. Limited to Nested Functions: The nonlocal keyword can only be used in nested functions, meaning it won't help if you want to modify a variable from a global or non-enclosing scope. This limitation means that its usage is more specific and doesn't apply universally.
     
  3. Not Ideal for Large Programs: In large programs, overuse of nonlocal can lead to tangled code where tracking changes to variables becomes difficult. It's generally better to use classes or other approaches for managing state in larger applications.

Nonlocal in Nested Functions

When you define a function inside another function in Python, it's called a nested function. Nested functions can be very useful for organizing code & creating helper functions that are only needed within a specific context. However, working with variables in nested functions can be tricky.

Let's say you have an outer function that defines a variable, & an inner function that wants to modify that variable. By default, if you try to assign a new value to the variable inside the inner function, Python will create a new local variable with the same name rather than modifying the outer variable.

For example: 

def outer_func():
    x = 10
    def inner_func():
        x = 20
        print(f"Inner x: {x}")
    inner_func()
    print(f"Outer x: {x}")

outer_func()
You can also try this code with Online Python Compiler
Run Code


Output:

Inner x: 20
Outer x: 10

Understanding Variable Scope in Python

Before understanding the nonlocal keyword in detail, it's important to have a solid understanding of variable scope in Python. Variable scope refers to the region of a program where a variable is visible & accessible.

In Python, there are two main types of variable scope: local & global. 

Local Scope

  • Variables defined inside a function are in the local scope of that function.
     
  • Local variables can only be accessed within the function where they're defined.
     
  • When the function finishes executing, the local variables are destroyed.
     

Example:

def my_func():
    x = 10  # Local variable
    print(x)
my_func()  
print(x)   # Error: x is not defined
You can also try this code with Online Python Compiler
Run Code


Output

10 

Global Scope:

  • Variables defined outside any function are in the global scope.
     
  • Global variables can be accessed from anywhere in the program, including inside functions.
     
  • They persist throughout the entire execution of the script.
     

Example:

x = 10  # Global variable
def my_func():
    print(x)
my_func()  
print(x)  
You can also try this code with Online Python Compiler
Run Code

 

Output

10
10


In addition to local & global scopes, Python also has a special scope called the nonlocal scope. This comes into play when you have nested functions.

Nonlocal Scope

  • Refers to variables defined in an enclosing function scope, but not in the global scope.
     
  • Allows nested functions to access & modify variables from outer functions.
     
  • Uses the nonlocal keyword to indicate that a variable is from an enclosing scope.
     

Example:

def outer_func():
    x = 10  # Nonlocal variable
    def inner_func():
        nonlocal x
        x = 20  # Modifies the nonlocal variable
    inner_func()
    print(x)  # Output: 20


outer_func()
You can also try this code with Online Python Compiler
Run Code


Output

20

 

Understanding these different scopes is crucial for working with variables effectively in Python, especially when dealing with nested functions & the nonlocal keyword.

Expanding the Scope: Python Nonlocal in Larger Scripts

While the examples we've seen so far have been relatively small, the nonlocal keyword can be particularly useful when working with larger Python scripts that involve multiple levels of nested functions.

Imagine you're building a complex data processing pipeline that involves several stages of transformation & analysis. You might have a main function that sets up the pipeline, and then a series of nested functions that handle each stage of the process.

For example:

def process_data(data):
    results = []
    
    def stage1(data):
        # Perform stage 1 processing
        processed_data = [item.upper() for item in data]
        return processed_data
    
    def stage2(data):
        # Perform stage 2 processing
        filtered_data = [item for item in data if len(item) > 5]
        return filtered_data
    
    def stage3(data):
        nonlocal results
        # Perform stage 3 processing
        results = [item[::-1] for item in data]
    
    # Run the pipeline
    data = stage1(data)
    data = stage2(data)
    stage3(data)
    
    return results


# Example usage
data = ['apple', 'banana', 'cherry', 'date']
final_results = process_data(data)
print(final_results)
You can also try this code with Online Python Compiler
Run Code


Output:

['ANANAB', 'YRREHC']


In this example, we have a process_data() function that sets up our data processing pipeline. Inside it, we define three nested functions: stage1(), stage2(), and stage3(), each handling a different stage of the process.

The stage3() function uses the nonlocal keyword to modify the results variable defined in the outer process_data() function. This allows us to accumulate the final results of our pipeline in a single variable that's accessible from the outer scope.

With nonlocal, we can avoid passing the results variable through each stage of the pipeline explicitly, which can make the code cleaner & more manageable to read.

Of course, this is just a simplified example, but the same principles apply to more complex scripts. When multiple levels of nested functions need to share and modify state, the nonlocal keyword can be a powerful tool for managing variable scope and keeping your code organized.

Note: Just remember to use nonlocal with caution and only when it is really required for your program's structure. Overusing nonlocal can make your code harder to understand & maintain, so always try to use alternative approaches like function arguments & return values when appropriate.

Examples

Let’s now look at a few examples to better understand the practical use of the nonlocal keyword.

Example 1: Modifying Outer Variable in a Nested Function

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

count_fn = counter()
print(count_fn())  
print(count_fn())  
You can also try this code with Online Python Compiler
Run Code

 

Output

1
2


Explanation: Here, the counter function defines a variable count. The nested increment function modifies the count variable using the nonlocal keyword. Each time we call count_fn(), the value of count is incremented by 1.

Example 2: Using nonlocal to Track State Across Function Calls

def make_multiplier(factor):
    result = 0    
    def multiplier(number):
        nonlocal result
        result = number * factor
        return result 
    return multiplier

times_two = make_multiplier(2)
print(times_two(5)
print(times_two(7))
You can also try this code with Online Python Compiler
Run Code

 

Output

10
14


Explanation: In this example, the make_multiplier function returns a nested function that multiplies a number by a given factor. The nonlocal keyword is used to modify the result variable, which tracks the outcome of each multiplication.


As you can see, assigning x = 20 inside inner_func() doesn't change the value of x in outer_func(). That's where the nonlocal keyword comes in.

Exploring Alternatives to Python Nonlocal

While the nonlocal keyword is a powerful tool for modifying variables in outer scopes, it's not the only way to achieve similar results. In some cases, you should look for alternative approaches that can make your code clearer or more efficient.

One common alternative is to use mutable objects like lists or dictionaries to store and update values. Instead of trying to modify a simple variable from an inner function, you can define a mutable object in the outer function and modify its contents in the inner function.


Let’s take an example using a list:

def outer_func():
    x = [10]
    def inner_func():
        x[0] = 20
        print(f"Inner x: {x[0]}")
    inner_func()
    print(f"Outer x: {x[0]}")

outer_func()
You can also try this code with Online Python Compiler
Run Code

 

Output:

Inner x: 20
Outer x: 20

 

In this case, we define x as a single-element list in outer_func(). Inside inner_func(), we modify the value of x[0] directly. Since lists are mutable, this change affects the list in the outer scope as well.

Another alternative is to use function arguments to pass values between scopes. Instead of relying on nonlocal variables, you can explicitly pass the required data into the inner function as arguments and return any necessary results.

For example: 

def outer_func():
    x = 10
    def inner_func(x):
        x = 20
        print(f"Inner x: {x}")
        return x
    x = inner_func(x)
    print(f"Outer x: {x}")


outer_func()
You can also try this code with Online Python Compiler
Run Code


Output:

Inner x: 20
Outer x: 20


In this approach, we pass x as an argument to inner_func(), modify its value inside the function, and then return the new value. We then assign the returned value back to x in outer_func().

Note: These alternatives can be helpful in situations where using nonlocal might make the code less readable or harder to understand. However, there are still cases where nonlocal is the most appropriate choice, especially when you need to modify multiple variables or have more complex nested structures.

Troubleshooting Python Nonlocal: Common Issues and Solutions

When using the nonlocal keyword in Python, you might encounter a few common issues. Understanding these issues and knowing how to resolve them can save you a lot of debugging time.

One common mistake is forgetting to declare a variable as nonlocal before using it. If you try to assign a value to a variable without first declaring it as nonlocal, Python will create a new local variable instead of modifying the outer variable.

Let’s discuss an example of this mistake:

def outer_func():
    x = 10
    def inner_func():
        x = 20  # Oops! Forgot to declare x as nonlocal
        print(f"Inner x: {x}")
    inner_func()
    print(f"Outer x: {x}")


outer_func()
You can also try this code with Online Python Compiler
Run Code


Output:

Inner x: 20
Outer x: 10


To fix this issue, you need to explicitly declare the variable as nonlocal before assigning to it:

def outer_func():
    x = 10
    def inner_func():
        nonlocal x
        x = 20
        print(f"Inner x: {x}")
    inner_func()
    print(f"Outer x: {x}")

outer_func()
You can also try this code with Online Python Compiler
Run Code


Output:

Inner x: 20
Outer x: 20


Another issue you might face is using nonlocal on a variable that doesn't exist in an outer scope. Python will raise a SyntaxError if you try to declare a variable as nonlocal when no such variable exists in any enclosing scope.

For example: 

def outer_func():
    def inner_func():
        nonlocal y  # Error! y is not defined in any outer scope
        y = 20
    inner_func()
outer_func()


To avoid this issue, make sure that the variable you're declaring as nonlocal is actually defined in an outer function scope.

One more thing to watch out for is using nonlocal in a way that makes your code harder to understand. Overusing nonlocal or modifying variables from distant scopes can make your code less readable and more error-prone.

Let’s take an example of code that can be confusing:

def outer_func():
    x = 10
    def inner_func1():
        nonlocal x
        x = 20
        def inner_func2():
            nonlocal x
            x = 30
        inner_func2()
    inner_func1()
    print(f"Outer x: {x}")
outer_func()
You can also try this code with Online Python Compiler
Run Code


While this code works, it's not immediately clear which function is modifying x and in what order. In cases like this, it might be better to use function arguments and return values to pass data between scopes, or to break up the nested functions into separate, top-level functions.

Frequently Asked Questions

What happens if I don’t use nonlocal inside a nested function?

If you don’t use nonlocal, Python will treat the variable in the nested function as a local variable, meaning it won’t modify the variable in the outer scope.

Can I use nonlocal with global variables?

No, nonlocal only works with variables in enclosing functions. To modify global variables, you must use the global keyword.

Is nonlocal always necessary for nested functions?

No, it’s only necessary when you want to modify a variable in the outer function scope. If you don’t need to modify it, you can simply access it without using nonlocal.

Conclusion

The nonlocal keyword in Python is a powerful tool that allows you to modify variables from an outer, non-global scope. It is especially useful for maintaining state between nested functions and avoiding the use of global variables. However, it should be used carefully, as it can introduce complexity into your code, especially in large programs.

You can also check out our other blogs on Code360.

Live masterclass