巨蟒异常链

在 Python 中有使用异常链的标准方法吗? 比如 Java 异常“ cause d by”?

这是一些背景资料。

我有一个带有一个主要异常类 DSError的模块:

 class DSError(Exception):
pass

在这个模块的某个地方会有:

try:
v = my_dict[k]
something(v)
except KeyError as e:
raise DSError("no key %s found for %s" % (k, self))
except ValueError as e:
raise DSError("Bad Value %s found for %s" % (v, self))
except DSError as e:
raise DSError("%s raised in %s" % (e, self))

基本上,这个代码片段应该只抛出 DSERror 并告诉我发生了什么以及为什么。问题是 try 块可能抛出许多其他异常,因此我希望能够执行以下操作:

try:
v = my_dict[k]
something(v)
except Exception as e:
raise DSError(self, v, e)  # Exception chained...

这是标准的蟒蛇方式吗?我在其他模块中没有看到异常链,那么在 Python 中是如何做到的呢?

69716 次浏览

Is this what you're asking for?

class MyError(Exception):
def __init__(self, other):
super(MyError, self).__init__(other.message)


>>> try:
...     1/0
... except Exception, e:
...     raise MyError(e)
Traceback (most recent call last):
File "<pyshell#27>", line 4, in <module>
raise MyError(e)
MyError: division by zero

If you want to store the original exception object, you can certainly do so in your own exception class's __init__. You might actually want to store the traceback as the exception object itself doesn't provide much useful information about where the exception occurred:

class MyError(Exception):
def __init__(self, other):
self.traceback = sys.exc_info()
super(MyError, self).__init__(other.message)

After this you can access the traceback attribute of your exception to get info about the original exception. (Python 3 already provides this as the __traceback__ attribute of an exception object.)

Exception chaining is only available in Python 3, where you can write:

try:
v = {}['a']
except KeyError as e:
raise ValueError('failed') from e

which yields an output like

Traceback (most recent call last):
File "t.py", line 2, in <module>
v = {}['a']
KeyError: 'a'


The above exception was the direct cause of the following exception:


Traceback (most recent call last):
File "t.py", line 4, in <module>
raise ValueError('failed') from e
ValueError: failed

In most cases, you don't even need the from; Python 3 will by default show all exceptions that occured during exception handling, like this:

Traceback (most recent call last):
File "t.py", line 2, in <module>
v = {}['a']
KeyError: 'a'


During handling of the above exception, another exception occurred:


Traceback (most recent call last):
File "t.py", line 4, in <module>
raise ValueError('failed')
ValueError: failed

What you can do in Python 2 is adding custom attributes to your exception class, like:

class MyError(Exception):
def __init__(self, message, cause):
super(MyError, self).__init__(message + u', caused by ' + repr(cause))
self.cause = cause


try:
v = {}['a']
except KeyError as e:
raise MyError('failed', e)