在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
为什么认为a
的{{1}}是int
的局部变量,list
时是全局的?这背后的理由是什么?
P.S。:我在阅读this thread后进行了实验。
答案 0 :(得分:5)
密钥可在the assignment statement的文档中找到:
将对象分配给单个目标以递归方式定义为 如下:
如果目标是标识符(名称)(例如
a = a + 1
):
- 如果名称未出现在当前代码的全局语句中 block:名称绑定到当前本地名称空间中的对象。
- 否则:名称绑定到当前全局中的对象 命名空间。
如果该名称已被绑定,该名称将被反弹。这可能会导致 先前绑定到该名称的对象的引用计数 达到零,导致对象被解除分配及其析构函数 (如果有的话)被召唤。
...
如果目标是订阅(例如
a[0] = a[0] + 1
):主要表达式 评估参考。它应该产生可变序列 对象(如列表)或映射对象(如字典)。 接下来,评估下标表达式。
在f
1 中,Python看到您将某个值绑定到a
,看到a
中没有使用global a
此范围内的语句并准备局部变量。然后它尝试评估表达式a + 1
,查找变量a
并找到未初始化的局部变量。这会产生UnboundLocalError
。
在f
2 中,Python发现您正在为变量a
的订阅分配一些值。它在本地命名空间中查找该变量并且无法找到它。然后它会遍历非本地命名空间(闭包),直到它到达全局命名空间。一旦在全局命名空间中找不到a
,它就会抛出NameError
。
答案 1 :(得分:-1)
你可以尝试这样做:
def f(a):
a += 1
print a
def g():
a = 3
f(a)
g()