重新提出exceptiontypes和消息,保留现有信息

我正在编写一个模块,并希望为它可以引发的exception(例如从所有foo模块的特定exception的FooError抽象类inheritance)有一个统一的exception层次结构。 这允许模块的用户捕获这些特定的exception,并在需要时明确处理它们。 但是由于某些其他的例外情况,模块中引发的许多例外情况都会引发。 例如由于文件上的OSError而导致某些任务失败。

我需要的是“包装”捕获的exception,使其具有不同的types和消息 ,以便通过捕获exception来获取信息。 但我不想丢失现有的types,消息和堆栈跟踪; 对于试图debugging问题的人来说,这是所有有用的信息。 顶级的exception处理程序是不好的,因为我试图装饰exception,然后再传播到堆栈的顶层,而顶层的处理程序太迟了。

这部分通过从现有types(例如class FooPermissionError(OSError, FooError) )中派生我的模块foo的特定exceptiontypes来解决,但是这并不能使以新types包装现有exception实例变得更容易,修改消息。

Python的PEP 3134 “exception链接和embedded式跟踪”讨论了Python 3.0中为“链接”exception对象所接受的更改,以指示在处理现有exception期间引发了新的exception。

我想要做的是相关的:我需要它在早期的Python版本中工作,我不需要链接,而只是为了多态。 什么是正确的方法来做到这一点?

Python 3引入了exception链 (如PEP 3134所述 )。 这可以引发一个exception,引用一个现有的exception作为“原因”:

 try: frobnicate() except KeyError as exc: raise ValueError("Bad grape") from exc 

被捕获的exception因此成为新exception的一部分(是“exception原因”),并且可用于任何代码捕获新exception。


Python 2中 ,看起来这个用例没有很好的答案(正如Ian Bicking和Ned Batchelder所描述的那样 )。 游民。

您可以使用sys.exc_info()来获取回溯,并用上述回溯引发新的exception(如PEP所述)。 如果你想保留旧的types和消息,你可以在exception时这样做,但只有在捕获你的exception时才有用。

例如

 import sys def failure(): try: 1/0 except ZeroDivisionError, e: type, value, traceback = sys.exc_info() raise ValueError, ("You did something wrong!", type, value), traceback 

当然,这实际上并没有那么有用。 如果是的话,我们不需要那个PEP。 我不build议这样做。

您可以创build自己的exceptiontypes,扩展您捕获的任何exception 。

 class NewException(CaughtException): def __init__(self, caught): self.caught = caught try: ... except CaughtException as e: ... raise NewException(e) 

但是大多数情况下,我认为捕获exception,处理exception,并且raise原始exception(并保留跟踪)或者raise NewException() 。 如果我打电话给你的代码,并收到你的一个自定义exception,我希望你的代码已经处理了你必须捕捉的任何exception。 因此我不需要自己访问它。

编辑:我发现这种分析方法抛出你自己的exception,并保持原来的exception。 没有漂亮的办法

对您的需求最直接的解决scheme应该是这样的:

 try: upload(file_id) except Exception as upload_error: error_msg = "Your upload failed! File: " + file_id raise RuntimeError(error_msg, upload_error) 

通过这种方式,您可以稍后打印您的消息以及上传function引发的具体错误