开发者

What are some elegant ways to abstract out repetitive exception handling in python?

When handling exceptions in python, I find myself repeating code quite often. The basic pattern is something of the form:

try:
  action_here()
except CommonException1:
  Action_always_taken_for_CommonException1()
except CommonException2:
  Action_always_taken_for_CommonException2()
except Exception:
  Default_action_always_taken()

What I would like to do is to some how abstract this repet开发者_如何学Pythonitive code out to a function or class. I know one way to do it is to call an exception handling function with the exception object, such as:

try:
  action_here()
except Exception as e:
  handle_exception(e)

Then in this function determine the exception based on class.

def handle_exception(e):
  if type(e) == type(CommonException1()):
    Action_always_taken_for_CommonException1()
  elif type(e) == type(CommonException2()):
    Action_always_taken_for_CommonException2())
  else:
    Default_action_always_taken()

This, however, feels clunky and inelegant. So my question is, what are some other alternatives to handling repetitive exception handling?


This situation is one of the main use cases for context managers and the with statement:

from __future__ import with_statement # Needed in 2.5, but not in 2.6 or later

from contextlib import contextmanager

@contextmanager
def handle_exceptions():
    try:
        yield # Body of the with statement effectively runs here
    except CommonException1:
        Action_always_taken_for_CommonException1()
    except CommonException2:
        Action_always_taken_for_CommonException2()
    except Exception:
        Default_action_always_taken()

# Used as follows
with handle_exceptions():
    action_here()


If you dislike the repeated if / elseif blocks, you could put your handles in a dict, keyed by type:

handlers = { type(CommonException1()) : Action_always_taken_forCommonException1,
             type(CommonException2()) : Action_always_taken_forCommonException2 }

def handle_exception(te):
  if te in handlers:
    handlers[te]()
  else:
    Default_action()

Which you could then run with:

try:
  action_here()
except Exception as e:
  handle_exception(type(e))

In addition: If you find yourself writing these try blocks frequently, then you could write your own context manager (see here). At the action_here() side, your code would then look like this:

with my_error_handling_context():
  action_here1()
  action_here2()

In this case, the handle_exception code would essentially be your context manager's __exit__ method (which will always get passed any exceptions raised during the with block).


Although a solution using a context manager (as proposed by others) is the most elegant, and would be what I would recommend too, I'd like to point out that your handle_exception function could be written more elegantly by re-raising the exception:

def handle_exception(e):
  try:
    raise e
  except CommonException1:
    Action_always_taken_for_CommonException1()
  except CommonException2:
    Action_always_taken_for_CommonException2()
  except Exception:
    Default_action_always_taken()
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜