如果不立即重新生成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处于活动状态,则会引发TypeError
exception,表明这是一个错误(如果在IDLE下运行,则会引发Queue.Empty
exception)。否则,
raise
评估expression式得到三个对象,使用None
作为省略expression式的值。 前两个对象用于确定exception的types和值。如果存在第三个对象而不是
None
,则它必须是一个回溯对象(请参阅标准types层次结构),并将其replace为当前位置作为发生exception的位置。 如果存在第三个对象而不是回溯对象或None
,则会引发TypeError
exception。
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议如下:
- 得到原来的exc_info
- 使用堆栈跟踪格式化原始错误消息
- 抛出一个新的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)