Python全局变量和局部变量
在Python 2.7中,运行以下代码:
def f():
a = a + 1
f()
会得到以下结果:
Traceback (most recent call last):
File "test.py", line 4, in <module>
f()
File "test.py", line 2, in f
a = a + 1
UnboundLocalError: local variable 'a' referenced before assignment
但是如果我把代码改成下面这样:
def f():
a[0] = a[0] + 1
f()
我就会遇到不同的错误:
Traceback (most recent call last):
File "test.py", line 4, in <module>
f()
File "test.py", line 2, in f
a[0] = a[0] + 1
NameError: global name 'a' is not defined
为什么Python在处理a
时把它当作局部变量,而在处理list
时又把它当作全局变量呢?这背后有什么原因吗?
附注:我是在阅读这个讨论后进行实验的。
2 个回答
-1
你能试着做类似这样的事情吗:
def f(a):
a += 1
print a
def g():
a = 3
f(a)
g()
7
关键在于文档中关于 赋值语句 的说明:
将一个对象赋值给一个目标的过程可以递归地定义如下。
如果目标是一个标识符(名字)(例如
a = a + 1
):
- 如果这个名字在当前代码块中没有出现在全局声明中:这个名字会绑定到当前本地命名空间中的对象。
- 否则:这个名字会绑定到当前全局命名空间中的对象。
如果这个名字之前已经绑定过,那么它会被重新绑定。这可能会导致之前绑定到这个名字的对象的引用计数变为零,从而使这个对象被释放,并调用它的析构函数(如果有的话)。
...
如果目标是一个下标(例如
a[0] = a[0] + 1
):首先会计算引用中的主要表达式。这个表达式应该返回一个可变的序列对象(比如列表)或者一个映射对象(比如字典)。接下来,会计算下标表达式。
在 f
1 中,Python 看到你正在给 a
绑定一个值,发现 a
在这个范围内没有出现在 global a
声明中,于是准备了一个本地变量。然后它尝试计算表达式 a + 1
,查找变量 a
,结果发现是一个未初始化的本地变量。这就导致了 UnboundLocalError
错误。
在 f
2 中,Python 看到你正在给变量 a
的一个下标赋值。它在本地命名空间中查找这个变量,但没有找到。然后它会向上查找非本地命名空间(闭包),直到找到全局命名空间。一旦在全局命名空间中也找不到 a
,就会抛出 NameError
错误。