"提升"之间的差异并且"提高e"?

时间:2016-03-22 11:57:46

标签: python exception

在python中,except块中的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        

3 个答案:

答案 0 :(得分:17)

这种情况没有区别。 raise没有参数will always raise the last exception thrown(也可以sys.exc_info()访问)。

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

try:
    raise Exception()
except Exception as e:
    if foo():
        e = OtherException()
    raise e

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

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

答案 1 :(得分:11)

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

使用raise,此代码:

try:
   int("hello")
except ValueError as e:
   raise

提供以下回溯:

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

使用raise e如下:

try:
   int("hello")
except ValueError as e:
   raise e

提供以下回溯

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

不同之处在于,在raise情况下,引用异常原始来源的正确行在引用中引用,但在raise e情况下,回溯引用raise e不是最初的原因。

因此,我建议始终使用raise而不是raise e

答案 2 :(得分:2)

可以使用sys.exc_info()清除“最后一个例外”(即sys.exc_clear())信息的结果。例如,如果catch块调用了一个函数foo(),它本身就有特殊的错误处理,就会发生这种情况。

在这种情况下,带有和不带参数的raise意味着不同的事情。 raise e仍会引用上面几行的异常,而raise速记会尝试引发None,这是一个错误。