Re-raise Python exception and preserve stack trace
我试图在一个线程中捕获异常并在主线程中重新引发它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import threading import sys class FailingThread(threading.Thread): def run(self): try: raise ValueError('x') except ValueError: self.exc_info = sys.exc_info() failingThread = FailingThread() failingThread.start() failingThread.join() print failingThread.exc_info raise failingThread.exc_info[1] |
这基本上起作用并产生以下输出:
1 2 3 4 | (<type 'exceptions.ValueError'>, ValueError('x',), <traceback object at 0x1004cc320>) Traceback (most recent call last): File"test.py", line 16, in <module> raise failingThread.exc_info[1] |
但是,异常的来源指向第16行,其中发生了重新加注。 原始异常来自第7行。如何修改主线程以使输出显示:
1 2 | Traceback (most recent call last): File"test.py", line 7, in <module> |
在Python 2中,您需要使用所有三个参数来引发:
1 | raise failingThread.exc_info[0], failingThread.exc_info[1], failingThread.exc_info[2] |
传递traceback对象作为第三个参数保留堆栈。
来自
If a third object is present and not
None , it must be a traceback
object (see section The standard type hierarchy), and it is
substituted instead of the current location as the place where the
exception occurred. If the third object is present and not a
traceback object orNone , aTypeError exception is raised. The
three-expression form ofraise is useful to re-raise an exception
transparently in an except clause, butraise with no expressions
should be preferred if the exception to be re-raised was the most
recently active exception in the current scope.
在这种特殊情况下,您不能使用no表达式版本。
对于Python 3(根据评论):
1 | raise failingThread.exc_info[1].with_traceback(failingThread.exc_info[2]) |
或者您可以使用
这段代码片段适用于python 2&amp;3:
1 2 3 4 5 | 1 try: ----> 2 raise KeyError('Default key error message') 3 except KeyError as e: 4 e.args = ('Custom message when get re-raised',) #The comma is not a typo, it's there to indicate that we're replacing the tuple that e.args pointing to with another tuple that contain the custom message. 5 raise |
你能写得这样吗:
1 2 3 4 | try: raise ValueError('x') except ValueError as ex: self.exc_info = ex |
然后使用异常中的stacktrace?