Python nested functions variable scoping [duplicate] Python nested functions variable scoping [duplicate] python python

Python nested functions variable scoping [duplicate]


In Python 3, you can use the nonlocal statement to access non-local, non-global scopes.

The nonlocal statement causes a variable definition to bind to a previously created variable in the nearest scope. Here are some examples to illustrate:

def sum_list_items(_list):    total = 0    def do_the_sum(_list):        for i in _list:            total += i    do_the_sum(_list)    return totalsum_list_items([1, 2, 3])

The above example will fail with the error: UnboundLocalError: local variable 'total' referenced before assignment

Using nonlocal we can get the code to work:

def sum_list_items(_list):    total = 0    def do_the_sum(_list):        # Define the total variable as non-local, causing it to bind        # to the nearest non-global variable also called total.        nonlocal total        for i in _list:            total += i    do_the_sum(_list)    return totalsum_list_items([1, 2, 3])

But what does "nearest" mean? Here is another example:

def sum_list_items(_list):    total = 0    def do_the_sum(_list):        # The nonlocal total binds to this variable.        total = 0        def do_core_computations(_list):            # Define the total variable as non-local, causing it to bind            # to the nearest non-global variable also called total.            nonlocal total            for i in _list:                total += i        do_core_computations(_list)    do_the_sum(_list)    return totalsum_list_items([1, 2, 3])

In the above example, total will bind to the variable defined inside the do_the_sum function, and not the outer variable defined in the sum_list_items function, so the code will return 0.

def sum_list_items(_list):    # The nonlocal total binds to this variable.    total = 0    def do_the_sum(_list):        def do_core_computations(_list):            # Define the total variable as non-local, causing it to bind            # to the nearest non-global variable also called total.            nonlocal total            for i in _list:                total += i        do_core_computations(_list)    do_the_sum(_list)    return totalsum_list_items([1, 2, 3])

In the above example the nonlocal assignment traverses up two levels before it locates the total variable that is local to sum_list_items.


Here's an illustration that gets to the essence of David's answer.

def outer():    a = 0    b = 1    def inner():        print a        print b        #b = 4    inner()outer()

With the statement b = 4 commented out, this code outputs 0 1, just what you'd expect.

But if you uncomment that line, on the line print b, you get the error

UnboundLocalError: local variable 'b' referenced before assignment

It seems mysterious that the presence of b = 4 might somehow make b disappear on the lines that precede it. But the text David quotes explains why: during static analysis, the interpreter determines that b is assigned to in inner, and that it is therefore a local variable of inner. The print line attempts to print the b in that inner scope before it has been assigned.


When I run your code I get this error:

UnboundLocalError: local variable '_total' referenced before assignment

This problem is caused by this line:

_total += PRICE_RANGES[key][0]

The documentation about Scopes and Namespaces says this:

A special quirk of Python is that – if no global statement is in effect – assignments to names always go into the innermost scope. Assignments do not copy data — they just bind names to objects.

So since the line is effectively saying:

_total = _total + PRICE_RANGES[key][0]

it creates _total in the namespace of recurse(). Since _total is then new and unassigned you can't use it in the addition.