When writing code, I often want to do something like this:
try: foo() except FooError: handle_foo() else: try: bar() except BarError: handle_bar() else: try: baz() except BazError: handle_baz() else: qux() finally: cleanup()
Obviously, this is completely unreadable. But it's expressing a relatively simple idea: execute a series of functions (or short code snippets), with an exception handler for each one, and stop as soon as a function fails. I imagine Python could provide syntactic sugar for this code, perhaps something like this:
# NB: This is *not* valid Python try: foo() except FooError: handle_foo() # GOTO finally block else try: bar() except BarError: handle_bar() # ditto else try: baz() except BazError: handle_baz() # ditto else: qux() finally: cleanup()
If no exceptions are raised, this is equivalent to
foo();bar();baz();qux();cleanup(). If exceptions are raised, they're handled by the appropriate exception handler (if any) and we skip to
cleanup(). In particular, if
bar() raises a
BazError, the exception will not be caught and will propagate to the caller. This is desirable so we only catch exceptions we're truly expecting to handle.
Regardless of syntactic ugliness, is this kind of code just a bad idea in general? If so, how would you refactor it? I imagine context managers could be used to absorb some of the complexity, but I don't really understand how that would work in the general case.