19

I've written a program that needs to deal with a function that can throw multiple exceptions. For each exception I catch I have some code that will handle it specifically.

However, I also have some code I want to run no matter which exception was caught. My current solution is a handle_exception() function which is called from each except block.

try:
    throw_multiple_exceptions()
except FirstException as excep:
    handle_first_exception()
    handle_exception()
except SecondException as excep:
    handle_second_exception()
    handle_exception()

Is there a better way to do this? I would like the code to look like this:

try:
    throw_multiple_exceptions()
except FirstException as excep:
    handle_first_exception()
except SecondException as excep:
    handle_second_exception()
except Exception as excep:
    handle_exception()
Stevoisiak
  • 23,794
  • 27
  • 122
  • 225
user4624535
  • 191
  • 1
  • 5

4 Answers4

18

how about PEP 0443? its awesome, and very scalable because all you have to do is code and register new handlers

from functools import singledispatch
@singledispatch
def handle_specific_exception(e): # got an exception we don't handle
    pass       

@handle_specific_exception.register(Exception1)
def _(e):
    # handle exception 1

@handle_specific_exception.register(Exception2)
def _(e):
    # handle exception 2

try:
    throw_multiple_exceptions()
except Exception as e:
    handle_specific_exception(e)
    handle_exception()
rbp
  • 1,850
  • 15
  • 28
  • 4
    OP didn't say which version of Python, so it's probably worth mentioning that this feature was introduced in Python 3.4 and that there is a [backport](https://pypi.python.org/pypi/singledispatch) available for 2.6 through 3.3. – John Y Jan 14 '16 at 19:07
  • Beautiful. This provides a way to function overload in a dynamic language, something I've missed. Thanks! – David Jay Brady Sep 11 '20 at 23:52
7

You could do something like:

try:
    throw_multiple_exceptions()
except FirstException, SecondException as excep:
    if isinstance(excep, FirstException):
        handle_first_exception()
    else:
        handle_second_exception()
    handle_exception()
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
2

In case there are a lot of exceptions to handle, I suggest the way as follows:

from exceptions import ZeroDivisionError, AssertionError, Exception

def handle_first_exception():
    print "First exception occurred"

def handle_second_exception():
    print "Second exception occurred"

def handle_exception():
    print "Exception occurred"

def throw_multiple_exceptions():    
    3/0                 # |-> will output "First exception occurred"
    assert 2 > 3        # |-> will output "Second exception occurred"
    [1, 2, 3].index(0)  # |-> will output "Exception occurred" 

if __name__ == '__main__':
    # more types of exceptions could be added to this dict
    exceptions = { ZeroDivisionError: handle_first_exception, AssertionError: handle_second_exception }

    try:
        throw_multiple_exceptions()
    except Exception as excep:
        if type(excep) in exceptions.keys():
            exceptions[type(excep)]()
        else:  handle_exception()
Quinn
  • 4,394
  • 2
  • 21
  • 19
1

You may create a generic routine and pass additional callable object (function), depending on raised exception type.

def handle_first_exception():
    pass

def handle_second_exception():
    pass

handlers = {
    FirstException: handle_first_exception
    SecondException: handle_second_exception
}

def empty_handler():
    pass

def handle_exception(f):
    f()  # call passed handler
    # common code goes here

try:
    throw_multiple_exceptions()
except Exception as e:
    handle_exception(handlers.get(type(e), empty_handler))

Although I'll agree on comment discussion, a lot of exceptions with a lot of different except clauses seems a little bit like a code smell.

Łukasz Rogalski
  • 22,092
  • 8
  • 59
  • 93
  • @rbp: To be fair, it's not a whole lot of lines longer than yours, and it's reasonably easy to understand. To me, this looks like what folks would use if they didn't have `singledispatch` available. – John Y Jan 14 '16 at 19:05