The Python nonlocal Keyword

Introduction

The Python nonlocal keyword is used to access and modify variables from an outer (but not global) scope in nested functions (i.e. non-local variables). It tells Python that a variable assigned in a nested function should refer to a variable in the nearest enclosing scope that is not global. Otherwise, Python will create a new variable in the local scope of the nested function.

It is similar to the global keyword, but operates on outer local scopes of nested functions rather than global scopes. Because of this similarity, the lesson about the global keyword is a recommended prerequisite.

Using the Python nonlocal Keyword

To use the nonlocal keyword, simply write nonlocal followed by the variable name within a nested function to reference an outer (but not global) scope variable:

nonlocal variable_name

The above statement will ensure that variable_name refers to a variable in an outer (non-global) scope.

Example:

def outer_function():
    outer_var = 10

    def inner_function():
        nonlocal outer_var
        outer_var = 20

    inner_function()
    print("Outer variable:", outer_var)

outer_function()

Output:

Outer variable: 20

In the example above, the nonlocal statement inside the inner_function() (line 5) indicates that outer_var refers to the variable declared in the outer function outer_function() (line 2). When the inner function modifies outer_var by setting it to 20 (line 6), it is the variable in the outer scope that changes. Consequently, when outer_var is printed outside the inner function (line 9), the output is 20.

What Happens Without nonlocal

If you don’t use the nonlocal keyword and attempt to assign a value to a variable from an outer scope within a nested function, Python will create a new local variable in the nested function instead.

Example:

def outer_function():
    outer_var = 10

    def inner_function():
        outer_var = 20  # This is a local variable here!

    inner_function()
    print("Outer variable:", outer_var)

outer_function()

Output:

Outer variable: 10

The only difference between this and the previous example’s code is the removal of the nonlocal outer_var statement in the inner_function(). Now, when outer_var is assigned a value inside inner_function() (line 5), it creates a new local variable within that function’s scope, not modifying the variable from the outer function. Therefore, when outer_var is printed (line 8), it remains unchanged and retains the value of 10.

nonlocal Does Not Create a Variable If It Does Not Exist

Unlike a global statement, nonlocal does not create a variable in an outer scope if one does not exist yet. The following example demonstrates this by generating an error.

Example:

def outer_function():
    def inner_function():
        nonlocal outer_var
        outer_var = 20

    inner_function()
    print("Outer variable:", outer_var)

outer_function()

Output:

...
SyntaxError: no binding for nonlocal 'outer_var' found

The above example generates a SyntaxError exception because the nonlocal statement in inner_function() (line 3) references a variable that does not exist yet.

nonlocal Will Bind to Variables in Higher Levels of Nesting

While multiple levels of nesting in functions is rare and should be avoided if possible for the sake of code simplicity and clarity, nonlocal does support it. If it doesn’t find the variable in a parent function, it will keep going up the hierarchy of nested functions until it finds one.

Example:

def outer_outer_function():
    outer_outer_var = None
    
    def outer_function():
        def inner_function():
            nonlocal outer_outer_var
            outer_outer_var = 20
    
        inner_function()
        print("Outer outer variable:", outer_outer_var)
    
    outer_function()
    
outer_outer_function()

Output:

Outer outer variable: 20

The example above has three levels of nested functions. inner_function() (line 5) is in outer_function() (line 4) , which is in outer_outer_function() (line 1). inner_function() references outer_outer_var in the nonlocal statement (line 6), which is a variable first declared by outer_outer_function(), two nesting levels up.

Drawbacks of Using Non-Local Variables

The use of non-local variables suffers from the same readability, maintainability, and testing drawbacks as the use of global variables within functions. However, because non-local variables are contained within the smaller scope of a single parent function, those drawbacks are less severe.

If you keep your functions small, the convenience of referencing non-local variables directly within inner functions rather than passing them as arguments might outweigh their drawbacks.

Summary & Reference for the Python nonlocal Keyword

The Python nonlocal keyword lets you modify and access variables from outer scopes within nested functions (a.k.a non-local scopes). Without it, functions attempting to assign a value to an outer scope variable create a local variable with the same name instead, potentially leading to unintended behavior.


To use the nonlocal keyword, simply write nonlocal followed by the variable name within a nested function to reference an outer (but not global) scope variable.

nonlocal variable_name

If the nonlocal keyword is omitted within a nested function, Python will create a new local variable with the same name as the variable from the outer scope.

def outer_function():
    outer_var = 10

    def inner_function():
        outer_var = 20  # This is a local variable here!

    inner_function()
    print("Outer variable:", outer_var)

outer_function()  # --> 10  - not modified by inner_function()

The nonlocal keyword does not create a variable in an outer scope if it doesn’t already exist, which differs from the behavior of the global keyword.

def outer_function():
    def inner_function():
        nonlocal outer_var  # This will raise a SyntaxError
        outer_var = 20

    inner_function()
    print("Outer variable:", outer_var)

outer_function()  # --> SyntaxError: no binding for nonlocal 'outer_var' found

While using nonlocal can be convenient, excessive reliance on non-local variables can lead to code readability and maintainability issues. It’s recommended to use non-local variables judiciously and consider alternative approaches for clearer code structure.