如何阻止 Python 删除名称绑定(bind),当该名称是
用于绑定(bind)捕获的异常?这是什么时候改变的
行为进入 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
在异常处理之前 显式绑定(bind),因此 Python 知道它是外部作用域中的名称。
在 Python 2.7 上,这运行良好并且 exc
名称保留下来用于
format
调用::
Got exception: ZeroDivisionError
太好了,这正是我想要的:except
子句绑定(bind)名称
我可以在函数的其余部分使用该名称来引用
异常对象。
在 Python 3.5 上,format
调用失败,因为显然 exc
绑定(bind)被删除::
Traceback (most recent call last):
File "<stdin>", line 8, in <module>
NameError: name 'exc' is not defined
为什么从外部作用域中删除了 exc
绑定(bind)?我们是什么意思
可靠地保留名称绑定(bind)以在 except
之后使用它
条款?
此更改何时进入 Python,记录在何处?
我将此报告为 Python 3 中的错误是否正确?
不,这不是错误。 Python 3 documentation for the try
/except
statement 中清楚明确地定义了您遇到的行为.还给出了这种行为的原因:
When an exception has been assigned using as target
, it is cleared at the end of the except
clause. This is as if
except E as N:
foo
was translated to
except E as N:
try:
foo
finally:
del N
This means the exception must be assigned to a different name to be able to refer to it after the except
clause. Exceptions are cleared because with the traceback attached to them, they form a reference cycle with the stack frame, keeping all locals in that frame alive until the next garbage collection occurs.
在 try
/except
block 范围之外声明名称不起作用的原因是因为您在as
子句。所以这就是 Python 删除的名称。
修复方法是在 as
子句中使用不同的名称来绑定(bind)异常,然后将全局变量分配给不同的异常名称:
>>> 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