Probably you have used a shortcut construct like that:
def conditional_result(switch): if switch: return result_a return result_b
else is not required, because the execution flow leaves the function once it comes across a
return statement. Have you ever felt doing the same with exceptions? In other words:
def conditional_error(switch): if switch: raise ErrorA raise ErrorB
Does that work the same way? Sure. Sure? After
ErrorA is raised — can the execution sequence ever magically re-enter the function
conditional_error right below the
if block, where it was exceptionally left? Generators can do this (with the
yield statement) .
The answer is that the above code is safe and behaves as expected, analogous to the
conditional_result function. The explanation from A Programmer’s Introduction to Python:
The raise statement does two things: it creates an exception object, and immediately leaves the expected program execution sequence to search the enclosing try statements for a matching except clause. The effect of a raise statement is to either divert execution in a matching except suite, or to stop the program because no matching except suite was found to handle the exception.
conditional_error function above this means: if there is a matching except clause, it is outside of the function (there definitely is no handler within the function, do you see one?). In this case the execution flow steps out of the function without saving the current state (as a generator or a co-routine in general would do) — the function is really, absolutely left and the program proceeds at a different point: the matching except clause. If there is no matching except clause, the program stops.
This is how it looks live:
class ErrorA(Exception): pass class ErrorB(Exception): pass def conditional_error(switch): if switch: raise ErrorA raise ErrorB try: conditional_error(True) except ErrorA: print("error A caught!") try: conditional_error(False) except ErrorB: print("error B caught!") conditional_error(False)
With the following output:
$ python test.py error A caught! error B caught! Traceback (most recent call last): File "test.py", line 26, in <module> conditional_error(False) File "test.py", line 11, in conditional_error raise ErrorB __main__.ErrorB