big*_*ose 6 python namespaces python-3.x
当该名称用于绑定捕获的异常时,如何阻止Python删除名称绑定?这种行为改变何时进入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))
Run Code Online (Sandbox Code Playgroud)
请注意,在异常处理之前exc显式绑定,因此Python知道它是外部作用域中的名称.
在Python 2.7上,这运行正常,exc名称仍然可用于format调用::
Got exception: ZeroDivisionError
Run Code Online (Sandbox Code Playgroud)
太棒了,这正是我想要的:except子句绑定名称,我可以在函数的其余部分使用该名称来引用异常对象.
在Python 3.5上,format调用失败,因为显然删除了exc
绑定::
Traceback (most recent call last):
File "<stdin>", line 8, in <module>
NameError: name 'exc' is not defined
Run Code Online (Sandbox Code Playgroud)
为什么exc从外部范围删除绑定?我们如何在
条款之后可靠地保留名称绑定以使用它except?
这个变化何时进入Python,它在哪里记录?
我是否应该将此报告为Python 3中的错误?
不,这不是一个错误.您正在体验的行为在try/ exceptstatement的Python 3文档中清楚明确地定义.这种行为的原因还给出了:
使用时分配了一个例外
as target,它在该except子句的末尾被清除.这就好像Run Code Online (Sandbox Code Playgroud)except E as N: foo被翻译成
Run Code Online (Sandbox Code Playgroud)except E as N: try: foo finally: del N这意味着必须将异常分配给不同的名称才能在该
except子句之后引用它.异常被清除,因为附加了回溯,它们与堆栈帧形成一个引用循环,使该帧中的所有本地生存,直到下一次垃圾收集发生.
声明try/ exceptblock 范围之外的名称不起作用的原因是因为您exc在as子句中使用了.这就是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
Run Code Online (Sandbox Code Playgroud)
正如Anthony Sottile在评论中指出的那样,try/ exceptcode 的反汇编也清楚地支持了文档的上述陈述:
>>> 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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
138 次 |
| 最近记录: |