Python 如果不立即重新引发异常回溯是隐藏的
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4825234/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Exception traceback is hidden if not re-raised immediately
提问by parxier
I've got a piece of code similar to this:
我有一段与此类似的代码:
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()
When func2raises an exception I receive the following traceback:
当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
From here I don't see where the exception is coming from. The original traceback is lost.
从这里我看不到异常的来源。原始回溯丢失。
How can I preserve original traceback and re-raise it? I want to see something similar to this:
如何保留原始回溯并重新提出它?我想看到类似的东西:
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
采纳答案by Jochen Ritzel
A blank raiseraises the last exception.
空白raise会引发最后一个异常。
# need to re-raise err so caller can do its own handling
if err:
raise
If you use raise somethingPython has no way of knowing if somethingwas an exception just caught before, or a new exception with a new stack trace. That's why there is the blank raisethat preserves the stack trace.
如果您使用raise somethingPython,则无法知道something是之前捕获的异常,还是带有新堆栈跟踪的新异常。这就是为什么有raise保留堆栈跟踪的空白。
回答by Senthil Kumaran
You can get a lot of information about the exception via the sys.exc_info()along with the tracebackmodule
您可以通过得到很多关于异常的信息sys.exc_info()与一起回溯模块
try the following extension to your code.
尝试对您的代码进行以下扩展。
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()
This would print, similar to what you wanted.
这将打印,类似于您想要的。
*** 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
回答by Gabi Purcaru
Your main function needs to look like this:
您的主要功能需要如下所示:
def main():
try:
func1()
except Exception, err:
# error processing
raise
This is the standard way of handling (and re-raising) errors. Here is a codepad demonstration.
这是处理(和重新引发)错误的标准方法。这是一个键盘演示。
回答by qris
It is possible to modify and rethrowan exception:
可以修改并重新抛出异常:
If no expressions are present,
raisere-raises the last exception that was active in the current scope. If no exception is active in the current scope, aTypeErrorexception is raised indicating that this is an error (if running under IDLE, aQueue.Emptyexception is raised instead).Otherwise,
raiseevaluates the expressions to get three objects, usingNoneas 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 orNone, aTypeErrorexception is raised.The three-expression form of
raiseis useful to re-raise an exception transparently in anexceptclause, butraisewith no expressions should be preferred if the exception to be re-raised was the most recently active exception in the current scope.
如果不存在表达式,则
raise重新引发在当前范围内处于活动状态的最后一个异常。如果当前范围内没有异常处于活动状态,TypeError则会引发异常,表明这是一个错误(如果在 IDLE 下运行,Queue.Empty则会引发异常)。否则,
raise计算表达式以获得三个对象,None用作省略表达式的值。前两个对象用于确定异常的类型和值。如果存在第三个对象但不存在
None,则它必须是回溯对象(请参阅标准类型层次结构部分),并且将其替换为发生异常的位置而不是当前位置。如果存在第三个对象而不是回溯对象或None,TypeError则会引发异常。的三表达式形式
raise对于在except子句中透明地重新引发异常很有用 ,但raise如果要重新引发的异常是当前范围内最近活动的异常,则不应首选表达式。
So if you want to modify the exception and rethrow it, you can do this:
所以如果你想修改异常并重新抛出它,你可以这样做:
try:
buggy_code_which_throws_exception()
except Exception as e:
raise Exception, "The code is buggy: %s" % e, sys.exc_info()[2]
回答by tvt173
While @Jochen's answer works well in the simple case, it is not capable of handling more complex cases, where you are not directly catching and rethrowing, but are for some reason given the exception as an object and wish to re-throw in a completely new context (i.e. if you need to handle it in a different process).
虽然@Jochen 的答案在简单的情况下效果很好,但它无法处理更复杂的情况,在这种情况下,您不直接捕获和重新抛出,而是出于某种原因将异常作为对象并希望重新抛出完全新上下文(即,如果您需要在不同的进程中处理它)。
In this case, I propose the following:
在这种情况下,我提出以下建议:
- get the original exc_info
- format the original error message, with stack trace
- throw a new exception with that full error message (stack trace incl.) embedded
- 获取原始的 exc_info
- 使用堆栈跟踪格式化原始错误消息
- 抛出一个带有完整错误消息(包括堆栈跟踪)的新异常
Before you do this, define a new exception type that you will rethrow later...
在执行此操作之前,请定义一个新的异常类型,稍后您将重新抛出该异常类型...
class ChildTaskException(Exception):
pass
In the offending code...
在违规代码中...
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)
Rethrow...
重新扔...
# again, a multiprocessing example of receiving that message through a pipe
error_msg = pcon.recv()
raise ChildTaskException(error_msg)

