"提高"和"提高e"之间的区别?

Dae*_*yth 23 python exception

在Python,有之间的差raiseraise e在除块?

dis 向我展示了不同的结果,但我不知道这意味着什么.

两者的最终行为是什么?

import dis
def a():
    try:
        raise Exception()
    except Exception as e:
        raise


def b():
    try:
        raise Exception()
    except Exception as e:
        raise e

dis.dis(a)
# OUT:   4           0 SETUP_EXCEPT            13 (to 16)
# OUT:   5           3 LOAD_GLOBAL              0 (Exception)
# OUT:               6 CALL_FUNCTION            0
# OUT:               9 RAISE_VARARGS            1
# OUT:              12 POP_BLOCK           
# OUT:              13 JUMP_FORWARD            22 (to 38)
# OUT:   6     >>   16 DUP_TOP             
# OUT:              17 LOAD_GLOBAL              0 (Exception)
# OUT:              20 COMPARE_OP              10 (exception match)
# OUT:              23 POP_JUMP_IF_FALSE       37
# OUT:              26 POP_TOP             
# OUT:              27 STORE_FAST               0 (e)
# OUT:              30 POP_TOP             
# OUT:   7          31 RAISE_VARARGS            0
# OUT:              34 JUMP_FORWARD             1 (to 38)
# OUT:         >>   37 END_FINALLY         
# OUT:         >>   38 LOAD_CONST               0 (None)
# OUT:              41 RETURN_VALUE        
dis.dis(b)
# OUT:   4           0 SETUP_EXCEPT            13 (to 16)
# OUT:   5           3 LOAD_GLOBAL              0 (Exception)
# OUT:               6 CALL_FUNCTION            0
# OUT:               9 RAISE_VARARGS            1
# OUT:              12 POP_BLOCK           
# OUT:              13 JUMP_FORWARD            25 (to 41)
# OUT:   6     >>   16 DUP_TOP             
# OUT:              17 LOAD_GLOBAL              0 (Exception)
# OUT:              20 COMPARE_OP              10 (exception match)
# OUT:              23 POP_JUMP_IF_FALSE       40
# OUT:              26 POP_TOP             
# OUT:              27 STORE_FAST               0 (e)
# OUT:              30 POP_TOP             
# OUT:   7          31 LOAD_FAST                0 (e)
# OUT:              34 RAISE_VARARGS            1
# OUT:              37 JUMP_FORWARD             1 (to 41)
# OUT:         >>   40 END_FINALLY         
# OUT:         >>   41 LOAD_CONST               0 (None)
# OUT:              44 RETURN_VALUE        
Run Code Online (Sandbox Code Playgroud)

Mar*_*oij 18

这种情况没有区别.raise没有参数将始终引发抛出的最后一个异常(也可以访问sys.exc_info()).

字节码不同的原因是因为Python是一种动态语言,并且解释器并不真正"知道" e引用当前正在处理的(未修改的)异常.但情况可能并非总是如此,请考虑:

try:
    raise Exception()
except Exception as e:
    if foo():
        e = OtherException()
    raise e
Run Code Online (Sandbox Code Playgroud)

e现在是什么?编译字节码时无法判断(仅在实际运行程序时).

在像你这样的简单示例中,Python解释器可能会"优化"字节码,但到目前为止还没有人这样做过.他们为什么要这样?它充其量只是微观优化,并且在模糊的条件下仍可能以微妙的方式打破.还有很多其他水果比这更低,并且开胃更有营养;-)


小智 16

两种形式产生的回溯有所不同.

使用raise,这段代码:

try:
   int("hello")
except ValueError as e:
   raise
Run Code Online (Sandbox Code Playgroud)

给出以下回溯:

Traceback (most recent call last):
  File "myfile.py", line 2, in <module>
    int("hello")
ValueError: invalid literal for int() with base 10: 'hello'
Run Code Online (Sandbox Code Playgroud)

使用raise e方法如下:

try:
   int("hello")
except ValueError as e:
   raise e
Run Code Online (Sandbox Code Playgroud)

给出以下回溯

Traceback (most recent call last):
  File "myfile.py", line 4, in <module>
    raise e
ValueError: invalid literal for int() with base 10: 'hello'
Run Code Online (Sandbox Code Playgroud)

区别在于,在这种raise情况下,引用异常的原始源的正确行在引用中被引用,但是在raise e回溯引用该raise e行而不是原始原因的情况下.

因此,我建议总是使用raise而不是raise e.

  • 您描述的行为适用于Python 2,但不适用于Python 3.在Python 3中,`raise e`不会吞下原始源,在这种情况下实际上会严格显示*more*信息. (8认同)
  • 这是非常重要的一点。我花了太多时间来追踪由于“raise e”而导致的错误的真正来源。 (2认同)