在Python中,有哪些优雅的方法可以抽象出重复的异常处理?

13 投票
3 回答
2167 浏览
提问于 2025-04-16 14:06

在处理Python中的异常时,我发现自己经常在重复写代码。基本的模式大概是这样的:

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

我想做的是把这些重复的代码抽象成一个函数或者类。我知道一种方法是调用一个异常处理函数,并传入异常对象,比如:

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

然后在这个函数里根据异常的类型来判断具体的异常。

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

不过,这样做感觉有点笨拙,不够优雅。所以我想问,还有哪些其他方法可以处理这些重复的异常处理呢?

3 个回答

5

虽然使用上下文管理器的解决方案(像其他人提到的那样)是最优雅的,我也会推荐这种方法,但我想指出的是,你的 handle_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()
6

如果你不喜欢重复写 ifelseif 的代码块,可以把处理方式放到一个字典里,用类型作为键:

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

然后你可以这样运行它:

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

另外:如果你发现自己经常写这些 try 块,那么你可以自己写一个上下文管理器(详细信息可以查看 这里)。在 action_here() 的地方,你的代码看起来会像这样:

with my_error_handling_context():
  action_here1()
  action_here2()

在这种情况下,handle_exception 的代码基本上就是你上下文管理器的 __exit__ 方法(这个方法会处理在 with 块中发生的任何异常)。

22

这种情况是上下文管理器和with语句的主要应用场景之一:

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

撰写回答