Q:

Python local name in nest function

I had a test for local variable in nest function,
I got the error as the following code:
# coding: utf-8

def func3():
    x = [1, 2, 3]

    def func2():
        print 'func2:', locals()
        x[0] += x[0]
        print 'func2:', locals()

    def func3():
        print 'func3:', locals()
        x = x[0]
        print 'func3:', locals()

    func2()
    print "-->", locals()

    func3()
    print "==>", locals()

if __name__ == '__main__':
    func3()

I got the error:
func2: {'x': [1, 2, 3]}

func2: {'x': [2, 2, 3]}

--> {'func3': <function func3 at 0x1076adde8>, 'func2': <function func2 at 0x1076ad6e0>, 'x': [2, 2, 3]}

func3: {}

Traceback (most recent call last):

  File "test.py", line 23, in <module>

    func3()

  File "test.py", line 19, in func3

    func3()
  File "test.py", line 13, in func3

    x = x[0]

UnboundLocalError: local variable 'x' referenced before assignment

Why did func2 and func3 have the different answers?

A:

If there is an assignment to a variable in a function, a local variable is created in that function and all references to the same name are assumed to be to that local variable. Otherwise, the references to a variable are assumed to go to an outer scope.
In func2 there is no assignment to x (there is an assignment to x[0], but that's not the same thing). Therefore it refers to the outer x and everything works correctly.
However, in func3 there is an assignment to x. Therefore x in that function refers to a new variable local to that function, and x = x[0] is wrong because it tries to read from an uninitialized variable.
In Python 3, you can put nonlocal x in func3 to assign to the outer x instead. In Python 2, there is no simple way to assign to a variable from an outer non-global scope. The usual workaround is to use indexing like in func2 or write to an attribute (x.attr = val).

