Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

The nonlocal Declaration

00:00 What if you need to modify a value in an enclosing function? The global declaration won’t work, because the variable is not in the global namespace. In this case, you can use the nonlocal declaration.

00:16 In this example, the enclosed function g() wants to change the variable x that was defined in the enclosing function f(). When you run the function f(), then you will see that x still has the value 20 when it is printed after the function g() was called.

00:38 That is because a new name x with the value 40 is added to the local namespace of the enclosed function g(). Using a global declaration won’t work in this case, because x is not in the global namespace. As you can see, the value of x is still 20 when it was printed after the function g() was called. In fact, the global x statement not only fails to provide access to x in the enclosing scope, it also creates an object called x in the global scope whose value is 40.

01:26 If you want to modify the value of x from inside the enclosed function g(), you need to use the nonlocal keyword instead of the global keyword. Names specified after the nonlocal keyword refer to variables in the nearest enclosing scope, which is, in this case, the variable x in the enclosing function f(). As you can see, after running the function f(), the value of x changed to 40 from within the enclosed function g().

02:04 The global and nonlocal keywords give developers a lot of flexibility, but that flexibility also comes with some caveats we’ll have a look at in the final lesson of this section.

Avatar image for SatyaRavipati

SatyaRavipati on March 6, 2021

Hi Johan, this great tutorial and content is very detailed and valuable. I have a quick question from below code snippet, can you help me with it.

def e():
    x = 10
    def f():
        x = 20
        def g():
            nonlocal x
            print(x)
        g()
    f()

When I want to acess value of x (value 10 in function e) inside g(), is it possible to get this using namespace?

Avatar image for Bartosz Zaczyński

Bartosz Zaczyński RP Team on March 8, 2021

@SatyaRavipati TL;DR You can’t unambiguously access the variable x in the outermost scope.

Variables have a scope, which defines their visibility and lifetime. Scopes are structured in a hierarchy that the Python interpreter can scan through when searching for a given symbol. It always starts looking for variables in the local scope. If no variable with the expected name is found in the local scope, then it moves on to the nearest enclosing scope and continues until the global scope. Finally, Python will try to look for the variable among the built-in symbols.

That is known as the LEGB rule, which is short for Local, Enclosing, Global, and Built-in.

Normally, when you declare a local variable with the same name as a global one or a variable defined in the enclosing scope, it’s known as masking or shadowing:

x = 42  # Global variable

def function():
    x = 555  # Local variable shadows the global one
    print(x)

But, what if you wanted to modify the global variable x, or “rebind” it, instead of creating a new local variable with the same name in the function? You can take advantage of the global keyword in such a case:

x = 42  # Global variable

def function():
    global x
    x = 555  # Global variable with a new value

function()
print(x)

This will instruct Python to look for an existing variable in the global scope straight away. Interestingly, you don’t need to declare a variable like that if you only want read access to the global variable:

x = 42  # Global variable

def function():
    print(x)  # Reads the global variable

(Note: You can modify the value of a global variable without using the global keyword if it’s a mutable data type, but you won’t be able to rebind the variable to another object.)

Things get more interesting when you add intermediate scopes to the mix. Using the nonlocal keyword lets you assign new values or “rebind” existing variables that are neither local nor global but somewhere in the middle:

x = 42  # Global variable

def outer():
    x = 555  # Local to outer()
    def medium():
        x = 777  # Local to medium()
        def inner():
            nonlocal x
            x = 999  # Rebind x local to medium()

Unfortunately, it won’t tell you upfront which of the enclosing scopes will be modified as Python will look for the variable outwards and stop at the first occurrence.

Become a Member to join the conversation.