如果不立即重新引发,则隐藏异常回溯

2024-04-29 19:40:50 发布

您现在位置: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 <module>
    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 <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

Tags: inpytestifmaindefsysline
3条回答

有可能modify and rethrow出现异常:

If no expressions are present, raise re-raises the last exception that was active in the current scope. If no exception is active in the current scope, a TypeError exception is raised indicating that this is an error (if running under IDLE, a Queue.Empty exception is raised instead).

Otherwise, raise evaluates the expressions to get three objects, using None as the value of omitted expressions. The first two objects are used to determine the type and value of the exception.

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 or None, a TypeError exception is raised.

The three-expression form of raise is useful to re-raise an exception transparently in an except clause, but raise with no expressions should be preferred if the exception to be re-raised was the most recently active exception in the current scope.

因此,如果要修改异常并重新引发它,可以执行以下操作:

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

空白raise引发最后一个异常。

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

如果使用raise something,Python无法知道something是之前捕获的异常,还是具有新堆栈跟踪的新异常。这就是为什么保留栈跟踪的空白^ {< CD1> }。

Reference here

您可以通过sys.exc_info()traceback模块获得关于异常的许多信息

请尝试对代码进行以下扩展。

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

相关问题 更多 >