如果不立即重新生成exception追踪,则隐藏

我有一个类似于这样的代码:

import sys def func1(): func2() def func2(): raise Exception('test error') def main(): err = None try: func1() except: err = sys.exc_info()[1] pass # some extra processing, involving checking err details (if err is not None) # need to re-raise err so caller can do its own handling if err: raise err if __name__ == '__main__': main() 

func2引发exception时,我收到以下回溯:

 Traceback (most recent call last): File "err_test.py", line 25, in <module> main() File "err_test.py", line 22, in main raise err Exception: test error 

从这里我看不到exception来自哪里。 原来的追踪丢失。

我怎样才能保留原始的回溯并重新提高呢? 我想看到类似这样的事情:

 Traceback (most recent call last): File "err_test.py", line 26, in <module> main() File "err_test.py", line 13, in main func1() File "err_test.py", line 4, in func1 func2() File "err_test.py", line 7, in func2 raise Exception('test error') Exception: test error 

空白的raise引发了最后一个exception。

 # need to re-raise err so caller can do its own handling if err: raise 

如果您使用raise something方法,Python无法知道是否有something是之前捕获的exception,或者是带有新堆栈跟踪的新exception。 这就是为什么保留堆栈跟踪的空白raise

在这里引用

可以修改和重新抛出exception:

如果不存在任何expression式,则raise重新引发当前作用域中活动的最后一个exception。 如果当前范围中没有exception处于活动状态,则会引发TypeErrorexception,表明这是一个错误(如果在IDLE下运行,则会引发Queue.Emptyexception)。

否则, raise评估expression式得到三个对象,使用None作为省略expression式的值。 前两个对象用于确定exception的types和值。

如果存在第三个对象而不是None ,则它必须是一个回溯对象(请参阅标准types层次结构),并将其replace为当前位置作为发生exception的位置。 如果存在第三个对象而不是回溯对象或None ,则会引发TypeErrorexception。

raise的三种expressionforms有助于在except子句中透明地重新引发exception,但如果要重新引发的exception是当前作用域中最近活动的exception,则不应该优先使用expression式进行引发。

所以如果你想修改exception并重新抛出它,你可以这样做:

 try: buggy_code_which_throws_exception() except Exception as e: raise Exception, "The code is buggy: %s" % e, sys.exc_info()[2] 

您可以通过sys.exc_info()和traceback模块获取有关exception的大量信息

尝试以下扩展到您的代码。

 import sys import traceback def func1(): func2() def func2(): raise Exception('test error') def main(): try: func1() except: exc_type, exc_value, exc_traceback = sys.exc_info() # Do your verification using exc_value and exc_traceback print "*** print_exception:" traceback.print_exception(exc_type, exc_value, exc_traceback, limit=3, file=sys.stdout) if __name__ == '__main__': main() 

这将打印,类似于你想要的。

 *** print_exception: Traceback (most recent call last): File "err_test.py", line 14, in main func1() File "err_test.py", line 5, in func1 func2() File "err_test.py", line 8, in func2 raise Exception('test error') Exception: test error 

你的主要function需要如下所示:

 def main(): try: func1() except Exception, err: # error processing raise 

这是处理(和重新提升)错误的标准方式。 这是一个键盘演示。

虽然@ Jochen的答案在简单的情况下效果很好,但它不能处理更复杂的情况,在这种情况下,您不是直接捕捉和重新投掷,而是出于某种原因将exception作为对象并希望完全重新投掷新的上下文(即如果你需要在不同的过程中处理它)。

在这种情况下,我build议如下:

  1. 得到原来的exc_info
  2. 使用堆栈跟踪格式化原始错误消息
  3. 抛出一个新的exception与embedded完整的错误信息(堆栈跟踪)

在执行此操作之前,先定义一个新的exceptiontypes,稍后再重新抛出…

 class ChildTaskException(Exception): pass 

在有问题的代码中…

 import sys import traceback try: # do something dangerous except: error_type, error, tb = sys.exc_info() error_lines = traceback.format_exception(error_type, error, tb) error_msg = ''.join(error_lines) # for example, if you are doing multiprocessing, you might want to send this to another process via a pipe connection.send(error_msg) 

再次引发…

 # again, a multiprocessing example of receiving that message through a pipe error_msg = pcon.recv() raise ChildTaskException(error_msg)