可能重复:
referenced before assignment error in python
local var referenced before assignment
好的,我只是试着看一下变量范围如何工作并在以下情况下运行。全部从终端跑出来:
x = 1
def inc():
x += 5
inc()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in inc
UnboundLocalError: local variable 'x' referenced before assignment
所以我思考得很好,也许我的方法无法访问x,所以我尝试了:
def inc():
print x
1
所以这很有效。现在我知道我可以这样做:
def inc():
global x
x += 1
这会奏效。但我的问题是为什么第一个例子失败了。我的意思是我希望自print x
起作用,x在函数内部可见,那么为什么x + = 5会失败?
答案 0 :(得分:35)
与采用“真正的”词法范围的语言不同,Python选择为变量设置特定的“命名空间”,无论是global
,nonlocal
还是本地。可以说,让开发人员有意识地编写这样的命名空间代码更加明确,因此更容易理解。我认为这种复杂性会使语言变得更加笨拙,但我想这完全取决于个人偏好。
以下是有关global
的一些示例: -
>>> global_var = 5
>>> def fn():
... print(global_var)
...
>>> fn()
5
>>> def fn_2():
... global_var += 2
... print(global_var)
...
>>> fn_2()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fn_2
UnboundLocalError: local variable 'global_var' referenced before assignment
>>> def fn_3():
... global global_var
... global_var += 2
... print(global_var)
...
>>> fn_3()
7
相同的模式也可以应用于nonlocal
变量,但此关键字仅适用于后面的Python版本。
如果您想知道,nonlocal
用于变量不是全局变量但不在函数定义范围内的变量。例如,def
中的def
,这是一种常见情况,部分原因是由于缺少多语句lambda。虽然在早期的Pythons中有一个黑客可以绕过这个功能的缺乏,我依旧记得它涉及使用单个元素列表......
请注意,写入变量是需要这些关键字的地方。只是阅读它们并不含糊,因此不需要。除非内部def
使用与外部变量名称相同的变量名称,否则应该避免诚实。
答案 1 :(得分:20)
当Python解析函数时,它会记录变量赋值的时间。当存在赋值时,它默认假定该变量是局部变量。要声明赋值引用全局变量,必须使用global
声明。
当您访问函数中的变量时,会使用LEGB scoping rules查找其值。
所以,第一个例子
x = 1
def inc():
x += 5
inc()
产生UnboundLocalError
,因为Python确定x
内的inc
为局部变量,
访问x
时可以使用第二个示例
def inc():
print x
因为在这里,根据LEGB规则,Python在本地范围内查找x
,找不到它,然后在扩展范围内查找它,仍然找不到它,最后查找它在全球范围内成功。
答案 2 :(得分:7)
当函数定义时,决定函数的本地名称:
>>> x = 1
>>> def inc():
... x += 5
...
>>> inc.__code__.co_varnames
('x',)
在这种情况下,x
存在于本地名称空间中。 x += 5
的执行需要x
的预先存在的值(对于整数,它类似于x = x + 5
),并且这在函数调用时失败,因为本地名称是未绑定的 - 这正是为什么异常UnboundLocalError
被命名为。
比较其他版本,其中x
不是本地变量,因此可以在全局范围内解析:
>>> def incg():
... print(x)
...
>>> incg.__code__.co_varnames
()