Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested function definitions and scope (UnboundLocalError) [duplicate]

Why is the following code invalid:

def foo1(x=5):
    def bar():
        if x == 5:
            x = 6
        print(x)
    bar()

While this code is valid:

def foo2(x=5):
    def bar():
        if x == 5:
            print('ok')
        print(x)
    bar()

foo2() will do exactly what you expect, but foo1() will give a UnboundLocalError: local variable 'x' referenced before assignment at the line if x == 5:. Why does altering the value of x later on in the code make this conditional invalid?

like image 471
Kahr Kunne Avatar asked Dec 01 '25 06:12

Kahr Kunne


1 Answers

Python needs first to detect what variables are local, and which variable are fetched from an outer scope. In order to do that it looks for assignments, like:

def foo1(x=5):
    def bar():
        if x == 5:
            x = 6 # an assignment, so local variable
        print(x)
    bar()

The point is, that the assignment can happen anywhere. For instance on the last line. Nevertheless, from the moment there is an assignment somewhere x is local. So in your first code fragment, x is a local variable. But you fetch it before it is assigned (bounded), so Python will error on it.

In python-3.x you can use the nonlocal keyword to access x from an outer scope:

def foo1(x=5):
    def bar():
        nonlocal x
        if x == 5:
            x = 6
        print(x)
    bar()

For python-2.x, you can for instance assign the variable to the function, like:

def foo1(x=5):
    def bar():
        if bar.x == 5:
            bar.x = 6
        print(bar.x)
    bar.x = x
    bar()

Note however that the two are not equivalent. Since in the former if you alter x, it will be alter the x in the foo1 scope as well. In the latter example you only modify bar.x. Of course if these are mutable objects, you alter the same object.

like image 105
Willem Van Onsem Avatar answered Dec 02 '25 19:12

Willem Van Onsem