带有 except 块的变量范围:Python 2 和 3 之间的区别



我在Python 2.7和Python 3.7之间遇到了局部变量作用域的奇怪差异。

考虑这个人工脚本unboundlocalexception.py(我意识到我可以在 exexcept 之后使用 else-block,但我从更长的函数中提取了此示例(:

def foo():
arithmetic_error = None
try:
y = 1.0 / 0
except ZeroDivisionError as arithmetic_error:
print("I tried to divide by zero")
if arithmetic_error is None:
print("Correct division")
foo()

在 Python 2 下,它按照我的预期工作:

$ python2 unboundlocalexception.py 
I tried to divide by zero

但是,令人惊讶的是,在Python 3下,出现了UnboundLocalError!

$ python3 unboundlocalexception.py 
I tried to divide by zero
Traceback (most recent call last):
File "unboundlocalexception.py", line 11, in <module>
foo()
File "unboundlocalexception.py", line 8, in foo
if arithmetic_error is None:
UnboundLocalError: local variable 'arithmetic_error' referenced before assignment

这种差异是否记录在任何地方?

这种行为是在 Python 3 中引入的,以防止引用周期,因为异常目标 - 问题中的arithmetic_error- 保留对回溯的引用。

从语言参考

当异常已使用 作为目标分配时,将在 例外子句的结尾。这好像

except E as N:
foo

被翻译成

except E as N:
try:
foo
finally:
del N

这意味着必须将异常分配给不同的名称才能 能够在 EXCEPT 子句之后引用它。清除异常 因为附有回溯,它们形成了一个参考 使用堆栈帧循环,使该帧中的所有局部变量保持活动状态 直到下一次垃圾回收发生。

这最初记录在PEP3110。

最新更新