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))
请注意,在异常处理之前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/ 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
正如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
| 归档时间: | 
 | 
| 查看次数: | 138 次 | 
| 最近记录: |