Share Python code when handling multiple exception

2020-08-14 07:49发布

问题:

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()

回答1:

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()


回答2:

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()


回答3:

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()


回答4:

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.