在Python中封装异常

ana*_*nik 5 python pip exception python-2.7

如何将应用程序与从使用的库依赖项中蔓延的异常分离?

[app] --uses--> [lib] --dependson--> [dependency]
                                           / /
  x- <-propagates--o <---throwsexception--' /
   \                                       /
    `-----needstohandle,soimports-----> --'
Run Code Online (Sandbox Code Playgroud)

问题来自真实pip代码:

  1. 模块 A (req/req_set.py)依赖于模块 B
  2. 模块 B(下载)使用模块 C(请求)
  3. 模块A 导入模块 C来处理来自 C 的异常

如何在模块B中封装异常?要从模块 A 中删除对 C 的依赖吗?如何确保原始异常的原因和详细信息不丢失?换句话说,我如何用不同的名称重新引发异常?

下面的代码片段完成了所需的工作,但它仅适用于 Python 3:

 try:
     dependency_call()
 except DependencyError as exc:
     raise LibraryError from exc
Run Code Online (Sandbox Code Playgroud)

更新:我正在寻找 Python 2 兼容的解决方案,添加的 Python 3raise ... from ...几乎可以很好地实现这一点。

更新 2:封装异常的目标是捕获异常[lib]并重新抛出一个新异常以[app]保留堆栈跟踪,以便调试工具仍然可以遍历代码(对于仅限人类的解决方案,Alex Thornton 的答案应该很好) 。

Ale*_*ton 4

您可以通过引用基类来捕获任意异常Exception

except Exception as exc:
    raise ApplicationError from exc
Run Code Online (Sandbox Code Playgroud)

为了让这个from习惯用法在 Python 2 中工作,你必须修改你的自定义异常:

class ApplicationError(Exception):
    def __init__(self, cause, trace):
        self.cause = cause
        self.trace = trace
    def __str__(self):
        return '{origin}\nFrom {parent}'.format(origin=self.trace, 
                                                parent=self.cause)
Run Code Online (Sandbox Code Playgroud)

然后像这样提高它:

 except Exception, exc:
     raise ApplicationError(exc)
Run Code Online (Sandbox Code Playgroud)

然后,cause当它被引发时,它会打印出来,如果您决定捕获该,这也是您可以访问的属性ApplicationError