Python nonlocal

Summary: in this tutorial, you’ll learn about the Python nonlocal scopes and how to use the nonlocal keyword to change the variables of the nonlocal scopes.

Introduction to Python nonlocal scopes

In Python, you can define a function inside another function. For example:

def outer():
    print('outer function')

    def inner():
        print('inner function')

    inner()


outer()Code language: Python (python)

Output:

outer function
inner functionCode language: JavaScript (javascript)

In this example, we defined a function called outer.

Inside the outer function, we defined another function called inner. And we called the inner function from the inside of the outer function.

Often, we say that the inner function is nested in the outer function. In practice, you define nested functions when you don’t want these functions to be global.

Both outer and inner have access to the global and built-in scopes as well as their local scopes.

And the inner function also has access to its enclosing scope, which is the scope of the outer function.

From the inner() function perspective, its enclosing scope is neither local nor global. And Python calls this a nonlocal scope.

Let’s modify the outer and inner functions:

def outer():
    message = 'outer function'
    print(message)

    def inner():
        print(message)

    inner()


outer()Code language: Python (python)

Output:

outer function
outer functionCode language: JavaScript (javascript)

When we call the outer function, Python creates the inner function and executes it.

When the inner function executes, Python doesn’t find the message variable in the local scope. So Python looks for it in the enclosing scope, which is the scope of the outer function:

See the following example:

message = 'global scope'


def outer():

    def inner():
        print(message)

    inner()


outer()Code language: Python (python)

Output:

global scopeCode language: PHP (php)

In this example, Python searches for the message variable in the local scope of the inner function.

Since Python doesn’t find the variable, it searches for the variable in its enclosing scope, which is the scope of the outer function.

And in this case, Python goes up to the global scope to find the variable:

Python nonlocal Scopes - Variable Lookup

Python nonlocal keyword

To modify variables from a nonlocal scope in a local scope, you use the nonlocal keyword. For example:

def outer():
    message = 'outer scope'
    print(message)

    def inner():
        nonlocal message
        message = 'inner scope'
        print(message)

    inner()

    print(message)


outer()Code language: Python (python)

Output:

outer scope
inner scope
inner scope    

In this example, we use nonlocal keyword to explicitly instruct Python that we’re modifying a nonlocal variable.

When you use the nonlocal keyword for a variable, Python will look for the variable in the enclosing local scopes chain until it first encounters the variable name.

More importantly, Python won’t look for the variable in the global scope.

Consider the following example:

message = 'outer scope'


def outer():
    print(message)

    def inner():
        nonlocal message
        message = 'inner scope'
        print(message)

    inner()

    print(message)


outer()Code language: Python (python)

If you run this code, you’ll get the following error:

SyntaxError: no binding for nonlocal 'message' foundCode language: JavaScript (javascript)

From inside of the inner function, we use the nonlocal keyword for the message variable.

Therefore, Python searches for the message variable in the enclosing scope, which is the scope of the outer function.

Since the scope of the outer function doesn’t have message variable and Python doesn’t look further in the global scope, it issues an error:

Python nonlocal Scopes - nonlocal variable lookup

Summary

  • The enclosing scopes of inner functions are called nonlocal scopes.
  • Use the nonlocal keyword to modify the variable from the nonlocal scopes.
  • And Python will look up the nonlocal variables in the enclosing local scopes chain. It won’t search for the variable in the global scope.
Did you find this tutorial helpful ?