Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between "raise" and "raise e"?

In python, is there a difference between raise and raise e in an except block?

dis is showing me different results, but I don't know what it means.

What's the end behavior of both?

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         
like image 602
Daenyth Avatar asked Mar 22 '16 11:03

Daenyth


People also ask

What does raise E mean?

raise e would still have a reference to the exception caught a few lines above, while the raise shorthand would try to raise None , which is an error. Follow this answer to receive notifications.

What does raise e do in Python?

The raise keyword raises an error and stops the control flow of the program. It is used to bring up the current exception in an exception handler so that it can be handled further up the call stack.

Can we use raise without exception in Python?

Only an exception handler (or a function that a handler calls, directly or indirectly) can use raise without any expressions.

Can a function have a raise statement without having a try except block?

It doesn't matter whether this is happening in a try-except block or not. If there has been a caught exception, then calling raise will re-raise that exception.


2 Answers

There is a difference in the backtraces that the two forms generate.

Using raise, this code:

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

Gives the following backtrace:

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

Using raise e as follows:

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

Gives the following backtrace

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

The difference is that in the raise case, the correct line referencing the original source of the exception is quoted in the backtrace, but in the raise e case the traceback references the raise e line not the original cause.

Therefore, I recommend always using raise rather than raise e.

like image 117
Peter Lloyd Avatar answered Sep 17 '22 11:09

Peter Lloyd


There is no difference in this case. raise without arguments will always raise the last exception thrown (which is also accessible with sys.exc_info()).

The reason the bytecode is different is because Python is a dynamic language and the interpreter doesn't really "know" that e refers to the (unmodified) exception that is currently being handled. But this may not always be the case, consider:

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

What is e now? There is no way to tell when compiling the bytecode (only when actually running the program).

In simple examples like yours, it might be possible for the Python interpreter to "optimize" the bytecode, but so far no one has done this. And why should they? It's a micro-optimization at best and may still break in subtle ways in obscure conditions. There is a lot of other fruit that is hanging a lot lower than this and is more nutritious to boot ;-)

like image 24
Martin Tournoij Avatar answered Sep 18 '22 11:09

Martin Tournoij