为什么Python 3在这里引发NameError
?名称error
在第一行中定义,并在try...except
块中分配给它。这是解释器中的错误,还是我错过了从Python 2到3的语言定义的细微变化?
error = None
try:
raise Exception('Boom!')
except Exception as error:
pass
if error is not None:
raise error
这是使用Python 3.6.7执行时的回溯:
$ python3 nameerror.py
Traceback (most recent call last):
File "nameerror.py", line 8, in <module>
if error is not None:
NameError: name 'error' is not defined
使用Python 2.7.15,我们得到了预期的Boom!
:
$ python2 nameerror.py
Traceback (most recent call last):
File "nameerror.py", line 9, in <module>
raise error
Exception: Boom!
如果代码包装在函数中,则Python 3.6.7会引发UnboundLocalError
,而Python 2.7.15仍能按预期工作。
$ python3 unbound.py
Traceback (most recent call last):
File "unbound.py", line 13, in <module>
main()
File "unbound.py", line 9, in main
if error is not None:
UnboundLocalError: local variable 'error' referenced before assignment
奇怪的是,从异常处理程序中删除as error
可以修复NameError
。 UnboundLocalError
。
答案 0 :(得分:4)
这是intentional change in the except
semantics,用于解决在回溯中的帧与帧中的异常之间形成参考循环的问题:
为了解决与PEP 344相关的垃圾收集问题,除了Python 3中的语句将生成其他字节码以删除目标外,从而消除了参考周期。 Phillip J. Eby [9]提出的源到源翻译是
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
...
您只需将原始异常分配给其他名称即可保留原始异常,例如:
try:
raise Exception('Boom!')
except Exception as error:
saved_error = error # Use saved_error outside the block