在子句之后删除了"例外"子句中的名称绑定



当名称是 用于绑定捕获的异常?这是什么时候改变的 行为进入 Python?

我正在编写在Python 2和Python 3上运行的代码:

exc = None
try:
1/0
text_template = "All fine!"
except ZeroDivisionError as exc:
text_template = "Got exception: {exc.__class__.__name__}"
print(text_template.format(exc=exc))

请注意,exc在异常处理之前显式绑定,因此 Python 知道它是外部作用域中的一个名称。

在 Python 2.7 上,这运行良好,并且exc名称可以保留下来用于format调用:

Got exception: ZeroDivisionError

太好了,这正是我想要的:except子句绑定名称 我可以在函数的其余部分使用该名称来引用 异常对象。

在 Python 3.5 上,format调用失败,因为显然exc绑定已删除::

Traceback (most recent call last):
File "<stdin>", line 8, in <module>
NameError: name 'exc' is not defined

为什么从外部范围中删除exc绑定?我们的意思是 可靠地保留名称绑定,以便在except之后使用它 第?

这种变化是什么时候进入 Python 的,它在哪里记录?

我将其报告为 Python 3 中的错误是正确的吗?

不,这不是错误。您遇到的行为在try/except语句的 Python 3 文档中明确定义。还给出了此行为的原因:

当使用as target分配异常时,将在except子句的末尾清除该异常。这好像

except E as N:
foo

被翻译成

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

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

try/except块的范围之外声明名称不起作用的原因是您在as子句中使用了exc。所以这就是Python删除的名称。

解决方法是在as子句中使用不同的名称将异常绑定到,然后将全局变量分配给不同的异常名称:

>>> exc_global = None
>>> try:
1 / 0
text_template = "All fine!"
except ZeroDivisionError as exc:
exc_global = exc
text_template = "Got exception: {exc.__class__.__name__}"

>>> print(text_template.format(exc=exc_global))
Got exception: ZeroDivisionError

正如 Anthony Sottile 在评论中指出的那样,try/except代码的反汇编也清楚地支持文档所做的上述陈述:

>>> code = """
try:
1/0
text_template = "All fine!"
except ZeroDivisionError as exc:
text_template = "Got exception: {exc.__class__.__name__}"
"""
>>> from dis import dis
>>> dis(code)
2           0 SETUP_EXCEPT            16 (to 18)
3           2 LOAD_CONST               0 (1)
4 LOAD_CONST               1 (0)
6 BINARY_TRUE_DIVIDE
8 POP_TOP
4          10 LOAD_CONST               2 ('All fine!')
12 STORE_NAME               0 (text_template)
14 POP_BLOCK
16 JUMP_FORWARD            38 (to 56)
5     >>   18 DUP_TOP
20 LOAD_NAME                1 (ZeroDivisionError)
22 COMPARE_OP              10 (exception match)
24 POP_JUMP_IF_FALSE       54
26 POP_TOP
28 STORE_NAME               2 (exc)
30 POP_TOP
32 SETUP_FINALLY           10 (to 44)
6          34 LOAD_CONST               3 ('Got exception: {exc.__class__.__name__}')
36 STORE_NAME               0 (text_template)
38 POP_BLOCK
40 POP_EXCEPT
42 LOAD_CONST               4 (None)
>>   44 LOAD_CONST               4 (None)
46 STORE_NAME               2 (exc)
48 DELETE_NAME              2 (exc)
50 END_FINALLY
52 JUMP_FORWARD             2 (to 56)
>>   54 END_FINALLY
>>   56 LOAD_CONST               4 (None)
58 RETURN_VALUE

最新更新