我在python中遇到一个奇怪的错误。以下ipython日志总结了它:
In [10]: def confused(stuff):
....: print huh
....: return stuff
....:
In [11]: confused(87)
0
Out[11]: 87
In [12]: def confused(stuff):
....: print huh
....: huh += 1
....: return stuff
....:
In [13]: confused(9)
---------------------------------------------------------------------------
UnboundLocalError Traceback (most recent call last)
/home/max/verk/btr-email/build/x86_64/bin/ipython in <module>()
----> 1 confused(9)
/home/max/verk/btr-email/build/x86_64/bin/ipython in confused(stuff)
1 def confused(stuff):
----> 2 print huh
3 huh += 1
4 return stuff
UnboundLocalError: local variable 'huh' referenced before assignment
有效的函数和抛出错误的函数之间的唯一区别是+ = 1行,即使这样,它也会在以前工作的行上引发错误!如果我在方法的第二个版本中引用global huh
之前放置huh
,也不会抛出错误。
为什么添加一行我在变量中添加一行会突然从全局变量变为局部变量?
答案 0 :(得分:7)
在您的脚本中,huh
指的是全局变量。您无法将引用更改为函数中的全局变量,而无需明确告知python您想要执行的操作:
def confused(stuff):
global huh
print huh
huh += 1
return stuff
对于诸如整数,字符串,浮点数等不可变对象,这意味着您无法在不将其声明为global
的情况下对对象进行任何更改。对于可变对象,您可以更改对象项或属性,但仍然无法更改对象的引用。
这是范围的问题。由于huh
不在confused
的本地范围内,因此python会在全局范围内找到它。由于它是在全局范围内找到的,因此除非您明确表示要(正如我上面所做的那样使用global
),否则不能指定。但是,如果它是list
,则一旦找到列表,您就可以访问该列表的所有方法(包括__setitem__
,append
等。)
关于错误的位置,可以通过稍微dis
组装来清除:
>>> def confused(stuff):
... print huh
...
>>> import dis
>>> dis.dis(confused)
2 0 LOAD_GLOBAL 0 (huh)
3 PRINT_ITEM
4 PRINT_NEWLINE
5 LOAD_CONST 0 (None)
8 RETURN_VALUE
>>> def confused2(stuff):
... print huh
... huh += 1
...
>>> dis.dis(confused2)
2 0 LOAD_FAST 1 (huh)
3 PRINT_ITEM
4 PRINT_NEWLINE
3 5 LOAD_FAST 1 (huh)
8 LOAD_CONST 1 (1)
11 INPLACE_ADD
12 STORE_FAST 1 (huh)
15 LOAD_CONST 0 (None)
18 RETURN_VALUE
你可以看到在confused2
中,python已经在函数的第一行尝试LOAD_FAST
(意思是寻找局部变量)。但是,没有局部变量huh
因此存在异常。