给出以下代码:
a = 0
def foo():
# global a
a += 1
foo()
运行时,Python抱怨:UnboundLocalError:在赋值之前引用的局部变量'a'
但是,当它是字典时......
a = {}
def foo():
a['bar'] = 0
foo()
事情运行得很好......
任何人都知道为什么我们可以在第二块代码中引用一个,但不是第一个?
答案 0 :(得分:2)
不同之处在于,您在分配给a
的第一个示例中创建了一个隐藏全局a
的新本地名称a
。
在第二个示例中,您没有对a
进行分配,因此使用了全局a
。
Python的一个特殊之处在于 - 如果没有全局语句生效 - 对名称的赋值总是进入最内层范围。
答案 1 :(得分:1)
问题是更新。
您无法更新a
,因为它不是函数本地命名空间中的变量。就地更新分配操作无法更新a
。
有趣的是,a = a + 1
也失败了。
Python为这些语句生成稍微优化的代码。它使用“LOAD_FAST”指令。
2 0 LOAD_FAST 0 (a)
3 LOAD_CONST 1 (1)
6 INPLACE_ADD
7 STORE_FAST 0 (a)
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
请注意,在等号的左侧和右侧使用a
会导致此优化。
但是,您可以访问a
,因为Python会为您搜索本地和全局命名空间。
由于a
未出现在赋值语句的左侧,因此使用了另一种访问类型“LOAD_GLOBAL”。
2 0 LOAD_CONST 1 (0)
3 LOAD_GLOBAL 0 (a)
6 LOAD_CONST 2 ('bar')
9 STORE_SUBSCR
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
答案 2 :(得分:0)
a += 1
相当于a = a + 1
。通过分配变量a
,它变为本地变量。您尝试分配a + 1
的值失败,因为a
尚未绑定。
答案 3 :(得分:0)
这是一个非常常见的Python问题:如果你在一个函数中分配一个变量(正如你所做的那样,使用+=
),任何地方(在你使用它之前不一定)另一种方式),它不使用全局的。但是,由于您所做的实际上是“a = a + 1”,因此您在分配之前尝试访问a
(在表达式的右侧)。
尝试在函数开头使用global a
(但请注意,您将覆盖全局a
值。)
在第二个示例中,您没有分配变量a
,而只分配给其中一个项目。所以使用了全局字典a
。