我正在编写一个模块,并希望它可以引发的异常具有统一的异常层次结构(例如,从FooError抽象类继承所有foo模块的特定异常)。这使模块的用户可以捕获那些特殊的异常,并在需要时进行区别处理。但是模块中引发的许多异常是由于其他一些异常而引发的;例如,由于文件上的OSError而导致某些任务失败。
FooError
foo
我需要的是 “包装”捕获 到 的异常,以使其具有不同的类型和消息 ,以便通过捕获异常的方式在传播层次结构中进一步获取信息。但是我不想丢失现有的类型,消息和堆栈跟踪;这对于尝试调试问题的人来说都是有用的信息。顶级异常处理程序是不好的,因为我试图在异常扩展到传播堆栈之前对其进行修饰,并且顶级处理程序为时已晚。
这可以通过foo从现有类型(例如class FooPermissionError(OSError, FooError))派生模块的特定异常类型来部分解决,但这并没有使将现有异常实例包装为新类型或修改消息变得更加容易。
class FooPermissionError(OSError, FooError)
Python的PEP 3134 “异常链接和嵌入式回溯”讨论了Python 3.0中接受的“链接”异常对象的更改,以指示在处理现有异常期间引发了新异常。
我想做的是相关的:我需要它也可以在早期的Python版本中工作,并且我不需要链,而只需要多态。什么是正确的方法?
Python 3 引入了 异常链接 (如PEP 3134中所述)。这允许在引发异常时引用现有异常作为“原因”:
try: frobnicate() except KeyError as exc: raise ValueError("Bad grape") from exc
捕获到的异常(excKeyError)因此成为新异常ValueError的一部分(“原因”)。任何捕获新异常的代码都可以使用“原因”。
exc
通过使用此功能,__cause__可以设置属性。内置的异常处理程序还知道如何报告异常的“原因”和“上下文”以及回溯。
__cause__
在 Python 2中 ,该用例似乎没有很好的答案(如Ian Bicking和Ned Batchelder所述)。笨蛋