pythonscopeglobal-variableslocal-variablesshadowing

UnboundLocalError trying to use a variable (supposed to be global) that is (re)assigned (even after first use)


When I try this code:

a, b, c = (1, 2, 3)

def test():
    print(a)
    print(b)
    print(c)
    c += 1
test()

I get an error from the print(c) line that says:

UnboundLocalError: local variable 'c' referenced before assignment

or in some older versions:

UnboundLocalError: 'c' not assigned

If I comment out c += 1, all the prints are successful.

I don't understand: why does printing a and b work, if c does not? How did c += 1 cause print(c) to fail, even when it comes later in the code?

It seems like the assignment c += 1 creates a local variable c, which takes precedence over the global c. But how can a variable "steal" scope before it exists? Why is c apparently local here?


See also How to use a global variable in a function? for questions that are simply about how to reassign a global variable from within a function, and Is it possible to modify a variable in python that is in an outer (enclosing), but not global, scope? for reassigning from an enclosing function (closure).

See Why isn't the 'global' keyword needed to access a global variable? for cases where OP expected an error but didn't get one, from simply accessing a global without the global keyword.

See How can a name be "unbound" in Python? What code can cause an `UnboundLocalError`? for cases where OP expected the variable to be local, but has a logical error that prevents assignment in every case.

See How can "NameError: free variable 'var' referenced before assignment in enclosing scope" occur in real code? for a related problem caused by the del keyword.


Solution

  • Python treats variables in functions differently depending on whether you assign values to them from inside or outside the function. If a variable is assigned within a function, it is treated by default as a local variable. Therefore, when you uncomment the line, you are trying to reference the local variable c before any value has been assigned to it.

    If you want the variable c to refer to the global c = 3 assigned before the function, put

    global c
    

    as the first line of the function.

    As for python 3, there is now

    nonlocal c
    

    that you can use to refer to the nearest enclosing function scope that has a c variable.