Why can't I overwrite the value of an argument of an outer function if I use that variable in an if statement?

Boris :

I was writing a decorator that is initialized with an argument, and I tried setting that argument to None by default and then check if that argument is None and if so do argument = some_default_value. I've boiled down the issue I ran into:

This code works (it prints None):

def outer(arg=None):
    def inner():
        print(arg)
    inner()

outer()

and this code works (it prints 22):

def outer(arg=None):
    def inner():
        arg = 22
        print(arg)
    inner()

outer()

This code doesn't:

def outer(arg=None):
    def inner():
        if arg is None:
            arg = 22
        print(arg)
    inner()

outer()

I get the following error:

Traceback (most recent call last):
  File "test.py", line 8, in <module>
    outer()
  File "test.py", line 6, in outer
    inner()
  File "test.py", line 3, in inner
    if arg is None:
UnboundLocalError: local variable 'arg' referenced before assignment

Why does using the variable arg in an if statement make Python decide that it must be defined in that scope and not in an outer scope?

chepner :

The scope of a variable is determined when the function is defined. By assigning to arg, you make arg a local variable throughout the scope local to inner, which means if arg is None is now testing the as-yet undefined local variable arg, not the non-local variable defined by outer. (Put another way, the presence of an assignment statement in the body of the function makes the name local, not the actual execution of the statement, which creates the variable by that name.)

You could fix that by declaring arg as non-local in the body of inner:

def outer(arg=None):
    def inner():
        nonlocal arg

        if arg is None:
            arg = 22
        print(arg)
    inner()

outer()

though be aware that the change to arg is visible after the call to inner as well, because it is outer's local variable arg that you changed.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=194231&siteId=1