Skip to content
Home » Functions in Python – Variable Scopes in Nested Functions

Functions in Python – Variable Scopes in Nested Functions

Spread the love

Here’s another article in the Functions in Python series, about variable scopes in nested functions.

If you haven’t read the previous parts yet, feel free to do so. Here they are:

1) Introduction to Functions

2) Functions with Parameters

3) The return Statement

4) Mandatory Parameters

5) Optional Parameters

6) Mutable Optional Parameters

7) Keyword Arguments

8) Arbitrary Number of Positional Parameters

9) Arbitrary Number of Keyword Parameters

10) Arbitrary Number of Both Positional and Keyword Parameters

11) Nested Functions

12) Calling Functions in Other Functions

13) Assigning Functions to Variables

14) Functions As Parameters

15) Functions Returning Functions

16) Local and Global Variables

Today we’ll be talking about variable scopes in nested functions. We’ll also be talking about nonlocal variables. You can also read this article on scopes and this one on the nonlocal statement in Python if you want.

Variable Scopes

How do variables behave in nested functions? Let’s find out. Here’s our example:

def value_reader():
    value = 5
    print("in value_reader before nested_reader: x = ", value)
    def nested_reader():
        value = 8
        print("in nested_reader: x = ", value)
    nested_reader()
    print("in value_reader after nested_reader: x = ", value)

value = 2
print("in global scope before value_reader: x = ", value)
value_reader()
print("in global scope after value_reader: x = ", value)

The variable value is defined in 3 places:

– in global scope (value = 2)

– in the enclosing function value_reader – (value = 5)

– in the nested function nested_reader – (value = 8)

If we run the program, we’ll get the following output:

in global scope before value_reader: x =  2
in value_reader before nested_reader: x =  5
in nested_reader: x =  8
in value_reader after nested_reader: x =  5
in global scope after value_reader: x =  2

Your Panda3D Magazine

Make Awesome Games and Other 3D Apps

with Panda3D and Blender using Python.

Cool stuff, easy to follow articles.

Get the magazine here (PDF).

Global Variables in Nested Functions

Turns out that in each of the three scopes the local variable is used and has no effect on the other two. This is pretty straightforward. But what if we use global variables in nested functions? Let’s modify our program by adding just one line:

global value

in the nested function:

def value_reader():
    value = 5
    print("in value_reader before nested_reader: x = ", value)
    def nested_reader():
        global value
        value = 8
        print("in nested_reader: x = ", value)
    nested_reader()
    print("in value_reader after nested_reader: x = ", value)

value = 2
print("in global scope before value_reader: x = ", value)
value_reader()
print("in global scope after value_reader: x = ", value)

Now the output is:

in global scope before value_reader: x =  2
in value_reader before nested_reader: x =  5
in nested_reader: x =  8
in value_reader after nested_reader: x =  5
in global scope after value_reader: x =  8

Now there’s a difference. The enclosing function value_reader is still working on its local variable and does not affect the other two. The nested function, nested_reader, however, is now working on the global variable value and it changes it to 8. That’s why after the function has executed, the global variable is changed, but not the local one in the enclosing function.

Python Jumpstart Course

Learn the basics of Python, including OOP.

with lots of exercises, easy to follow

The course is available on Udemy.

Nonlocal Variables

So, the global keyword in a function or in a nested function makes the function work on the global variable. The global scope is often referred to as module scope, because the whole file where the script is written is a module. If the global keyword is used in a nested function, the global variable may be changed, but the variable in the enclosing function is not affected. But is there a way for the nested function to be able to affect the variable in the enclosing function? Yes, there are the so-called nonlocal variables.

If we want to use nonlocal variables, we use the nonlocal keyword. Two conditions must be met for nonlocal variables to work:

1) The nonlocal keyword must be used in the nested function.

2) The nonlocal variable must be defined in the enclosing function before the nested function is called.

If any of the two conditions is not met, we’ll get an error.

Nonlocal variables can’t affect global variables. Let’s modify our previous example so that it uses a nonlocal variable. The only change we need to make is use the nonlocal keyword instead of global:

def value_reader():
    value = 5
    print("in value_reader before nested_reader: x = ", value)
    def nested_reader():
        nonlocal value
        value = 8
        print("in nested_reader: x = ", value)
    nested_reader()
    print("in value_reader after nested_reader: x = ", value)

value = 2
print("in global scope before value_reader: x = ", value)
value_reader()
print("in global scope after value_reader: x = ", value)

Are the two conditions met? First, the nonlocal keyword is used in the nested function. Second, the nonlocal variable is defined in the enclosing function (value = 5) before the nested function is called. So, the conditions met, everything should work fine. Here’s the output:

in global scope before value_reader: x =  2
in value_reader before nested_reader: x =  5
in nested_reader: x =  8
in value_reader after nested_reader: x =  8
in global scope after value_reader: x =  2

It works! The nested function is now using the nonlocal variable, i.e. the one defined in the enclosing function. That’s why the variable in the enclosing function changes after calling the nested function. The global variable is untouched.

Blender Jumpstart Course

Learn the basics of 3D modeling in Blender.

step-by-step, easy to follow, visually rich

The course is available on Udemy and on Skillshare.

Let’s now see what would happen if the second condition were not met. We’ll comment out the definition of the nonlocal variable in the enclosing function:

def value_reader():
    # value = 5
    print("in value_reader before nested_reader: x = ", value)
    def nested_reader():
        nonlocal value
        value = 8
        print("in nested_reader: x = ", value)
    nested_reader()
    print("in value_reader after nested_reader: x = ", value)

value = 2
print("in global scope before value_reader: x = ", value)
value_reader()
print("in global scope after value_reader: x = ", value)

And here’s the output:

no binding for nonlocal 'value' found

So, we have an error. We would get the same error if the first condition were not met, i.e. if the nonlocal keyword were used in the enclosing function instead of the nested one.


Spread the love

Leave a Reply