python-如果未立即重新引发异常回溯,则将其隐藏
我有一段类似于以下的代码:
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引发异常时,我收到以下回溯:
Traceback (most recent call last):
File "err_test.py", line 25, in
main()
File "err_test.py", line 22, in main
raise err
Exception: test error
从这里我看不到异常的来源。 原始回溯丢失。
如何保留原始回溯并重新提出? 我想看类似的东西:
Traceback (most recent call last):
File "err_test.py", line 26, in
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
5个解决方案
104 votes
空白raise something会引发最后一个异常。
# need to re-raise err so caller can do its own handling
if err:
raise
如果您使用raise something,Python无法知道something是之前捕获的异常还是带有新堆栈跟踪的新异常。 这就是为什么有空白raise保留堆栈跟踪的原因。
这里参考
Jochen Ritzel answered 2019-10-03T09:41:28Z
59 votes
可以修改并抛出异常:
如果不存在任何表达式,则raise重新引发最后一个例外,即 在当前范围内处于活动状态。 如果没有异常在 当前范围,将引发except异常,表明这是 错误(如果在IDLE下运行,则会引发raise异常 代替)。
否则,raise使用以下方法评估表达式以获取三个对象 except作为省略表达式的值。 前两个对象是 用于确定异常的类型和值。
如果存在第三个对象而不是raise,则该对象必须是回溯 对象(请参阅标准类型层次结构部分),它是 代替当前位置作为当前位置 发生异常。 如果第三个对象存在而不是回溯 对象或except,会引发raise异常。
三表达 raise的形式可用于透明地重新引发异常 except子句,但如果没有表达式则应首选raise,如果 要重新引发的异常是最近活动的异常 在当前范围内。
因此,如果要修改异常并将其重新抛出,可以执行以下操作:
try:
buggy_code_which_throws_exception()
except Exception as e:
raise Exception, "The code is buggy: %s" % e, sys.exc_info()[2]
qris answered 2019-10-03T09:42:30Z
5 votes
您可以通过sys.exc_info()以及回溯模块获得有关该异常的大量信息。
请尝试以下代码扩展。
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
Senthil Kumaran answered 2019-10-03T09:43:08Z
4 votes
尽管@Jochen的答案在简单的情况下效果很好,但它无法处理更复杂的情况,在这种情况下,您不能直接捕获并重新抛出,但由于某种原因被赋予例外,因此希望将其完全抛出 新的上下文(即,如果您需要在其他过程中处理它)。
在这种情况下,我提出以下建议:
得到原始的exc_info
使用堆栈跟踪格式化原始错误消息
引发一个新的异常,内嵌完整的错误消息(包括堆栈跟踪信息)
在执行此操作之前,请定义新的异常类型,稍后将其重新抛出...
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)
tvt173 answered 2019-10-03T09:44:21Z
2 votes
您的主要功能应如下所示:
def main():
try:
func1()
except Exception, err:
# error processing
raise
这是处理(和重新引发)错误的标准方法。 这是一个键盘演示。
Gabi Purcaru answered 2019-10-03T09:44:54Z