python
中赋值操作都会在当前作用域的locals()
内部新绑定一个变量。因此如下的代码会报错:
def func1():
x = 1
print locals()
def func2():
print 'fun2:', locals()
x += x
print 'fun2:', locals()
func2()
print locals()
if __name__ == '__main__':
func1()
报错就是
UnboundLocalError: local variable 'x' referenced before ssignment
但是为什么把x
改成列表,然后以下面的方式:
def func1():
x = [1, 2, 3]
print locals()
def func2():
print 'fun2:', locals()
x[0] += x[0]
print 'fun2:', locals()
func2()
print locals()
if __name__ == '__main__':
func1()
输出是:
{'x': [1, 2, 3]}
fun2: {'x': [1, 2, 3]}
fun2: {'x': [2, 2, 3]}
{'func3': <function func3 at 0x7f89da00ac08>, 'x': [2, 2, 3], 'func2': <function func2 at 0x7f89da00ab90>}
但是如果把x[0] += x[0]
改成x = x[0]
又报错了。
求解释啊。。。已经懵了---
func2 在 func1 之内,其作用域的范围等同于闭包(至于什么是闭包,详见我的这篇文章:Python 的闭包和装饰器),因此 x 实际上是在父函数 func1 的作用域内,func2 调用它类似于 func1 调用全局变量,只能读取而不能直接改写 x。但是如果你使用列表对象的 x,则 x[0] 并非 x对象 ,而是 x 的元素,因此可以被改写。
其实这是 python 2 的一个bug,在 python 3 中引入了 nonlocal 语句,其类似于 global 语句,只不过是用来声明某个变量是父函数的那个变量,以便于子函数可以直接改写该变量。
在python 2 中,只有用列表对象了,不过在 python 3 中可以这么写:
具体详见 这里