收到“UnboundLocalError: 在赋值前引用了局部变量'e'”的错误,尽管变量已被初始化
[社区编辑以提供可复现的示例:]
def main():
e = None
print(locals())
while not e:
try:
raise Exception
except Exception as e:
pass
main()
产生
~/coding$ python3.3 quiz2.py
{'e': None}
Traceback (most recent call last):
File "quiz2.py", line 11, in <module>
main()
File "quiz2.py", line 5, in main
while not e:
UnboundLocalError: local variable 'e' referenced before assignment
[已编辑]以包含可复现的代码
我正在尝试运行一个循环,这个循环的条件是当变量 e==None
时继续执行。相关的代码如下:
print("\nThe current score list contains the following people's scores: ")
score_list = open("score_list.dat", "rb")
score_name = []
e = None
while not e:
try:
score = pickle.load(score_list)
name = pickle.load(score_list)
score_name.append([score, name])
except EOFError as e:
pass
score_list_sorted=sorted(score_list)
sort_list.close()
for item in score_list_sorted:
print("Score: ", item[0], "\t", item[1])
完整代码在这里: https://www.dropbox.com/s/llj5xwexzfsoppv/stats_quiz_feb24_2013.py
它需要的数据文件(为了让测验运行)在这个链接: https://www.dropbox.com/s/70pbcb80kss2k9e/stats_quiz.dat
main()
需要编辑,以使用正确的数据文件地址:
我收到的完整错误信息如下。这很奇怪,因为我在 while 循环之前就初始化了 e
。希望有人能帮我解决这个问题。谢谢!
Traceback (most recent call last):
File "<pyshell#217>", line 1, in <module>
main()
File "/Users/Dropbox/folder/stats_quiz_feb24_2013.py", line 83, in main
while not e:
UnboundLocalError: local variable 'e' referenced before assignment
2 个回答
这个错误是因为新的 try...except...
结构,这是 Python 3 的一个新特性。
你可以查看 PEP-3110 来了解更多。
在 Python 3 中,下面这个代码块
try:
try_body
except E as N:
except_body
...
在 Python 2.5 中是这样理解的
try:
try_body
except E, N:
try:
except_body
finally:
N = None
del N
...
所以在 Python 3 中,这个函数
def main():
e = None
print(locals())
while not e:
try:
raise Exception
except Exception as e:
pass
其实是等同于
def main():
e = None
print(locals())
if not e:
try:
raise Exception
except Exception as e:
pass
del e
if not e:
try:
raise Exception
except Exception as e:
pass
del e
...
e
被初始化了,但在第一个 try except
块执行后就被删除了。
因此,UnboundLocalError
是不可避免的。
嗯,我不知道具体是什么导致了这个问题,但你为什么不在出现异常时直接用 break
呢?这样你的循环就变成了:
while True:
try:
score = pickle.load(score_list)
name = pickle.load(score_list)
score_name.append([score, name])
except EOFError as e:
break
据我所知,这是一种常见的做法,可以实现“在没有异常的情况下继续循环”。
编辑:为什么会这样
看起来在 Python 3 中,一旦你退出了异常处理的范围,和这个异常相关的变量就会从命名空间中移除。我把代码改成了下面这样:
def main():
e = None
print(locals())
while not e:
try:
raise Exception
except Exception as e:
pass
print(locals())
main()
输出:
{'e': None}
{}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in main
UnboundLocalError: local variable 'e' referenced before assignment
在 Python 2 中并不是这样。由于赋值异常给变量的语法发生了变化,我并不感到惊讶它的语义也发生了变化。虽然我觉得这种行为是“令人惊讶的”(因为这不是你所期待的结果)。
无论如何,当出现异常时,正确退出循环的方法就是上面的代码。如果你想在异常处理的范围之外保留这个异常,我想你可以这样做:
def main():
e = None
print(locals())
while not e:
try:
raise Exception
except Exception as ex:
e = ex
print(locals())
main()
这会产生以下输出:
{'e': None}
{'e': Exception()}
但对于你的具体用例来说,你真的不应该这样做。