如何将traceback / sys.exc_info()值保存在变量中?


127

我想将错误的名称和追溯详细信息保存到变量中。这是我的尝试。

import sys
try:
    try:
        print x
    except Exception, ex:
        raise NameError
except Exception, er:
    print "0", sys.exc_info()[0]
    print "1", sys.exc_info()[1]
    print "2", sys.exc_info()[2]

输出:

0 <type 'exceptions.NameError'>
1 
2 <traceback object at 0xbd5fc8>

所需输出:

0 NameError
1
2 Traceback (most recent call last):
  File "exception.py", line 6, in <module>
    raise NameError

PS:我知道可以使用追溯模块轻松完成此操作,但是我想在此了解sys.exc_info()[2]对象的用法。


您是否尝试打印sys.exc_info()[x] .__ str __()?
2011年

3
您可能误解了程序中正在发生的事情:所谓的“ sys.exc_info()[2]对象”是回溯对象的实例(=您已经在使用回溯模块)。现在,您可以在不使用追溯模块中的辅助函数的情况下操作该对象,但这不会改变您仍在使用它的事实。:)
mac

1
因此,@ mac请使用或不使用辅助功能从该对象访问值来帮助我。
codersofthedark 2011年

1
@dragosrsupercool-正如我在下面的回答中提到的那样,您应该查看回溯文档。我提供了一个有关如何以文本方式检索数据的示例,但是该对象还有其他方法可以让您提取异常名称,代码行等。正确的选择实际上取决于您要如何操作之后的价值...
mac

1
我的回答另一个问题时可以帮助说明的细节-有联系!对于固定字符串,标准库回溯模块似乎还可以。如果要获取详细信息,请阅读源(<python install path>/Lib/traceback.py)以获取更多信息。
pythonlarry

Answers:


180

这是我的方法:

>>> import traceback
>>> try:
...   int('k')
... except:
...   var = traceback.format_exc()
... 
>>> print var
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ValueError: invalid literal for int() with base 10: 'k'

但是,您应该查看traceback文档,因为您可能会发现更合适的方法,这取决于您以后要如何处理变量...


1
我正在寻找一种不使用回溯模块的方法。有什么办法可以从该对象引用中打印回溯详细信息吗?sys.exc_info()[2]
codersofthedark 2011年

是的,这就是为什么我认为我们可以做类似sys.exc_info()[2] .format_exc()的原因,但是这不起作用。因此,我想知道如何从追溯对象sys.exc_info()中提取值。 [2]。任何想法?
codersofthedark

1
sys.exc_info()[2] .tb_text给出以下错误-> AttributeError:“ traceback”对象没有属性“ tb_text”
codersofthedark

4
@dragosrsupercool- sys.exc_info()[2].tb_frame.f_code.co_names[3],但是毫无意义...如果traceback在标准库中调用了一个模块,那是有原因的... :)
Mac

2
@codersofthedark traceback.format_exception(*sys.exc_info())是做到这一点的方法。但这在功能上等同于traceback.format_exc()
wizzwizz4

25

sys.exc_info()返回具有三个值(类型,值,回溯)的元组。

  1. 这里的类型获取正在处理的异常的异常类型
  2. 值是要传递给异常类的构造函数的参数
  3. traceback包含堆栈信息,例如发生异常的位置等。

例如,在以下程序中

try:

    a = 1/0

except Exception,e:

    exc_tuple = sys.exc_info()

现在,如果我们打印元组,则值将为this。

  1. exc_tuple [0]的值将为“ ZeroDivisionError
  2. exc_tuple [1]的值将是“ 整数除法或以零 ”(作为参数传递给异常类的字符串)
  3. exc_tuple [2]的值将是“ (某些内存地址)的引用对象

也可以通过简单地以字符串格式打印异常来获取上述详细信息。

print str(e)

对于Python3,exc_tuple [1](即值)是异常的实例,而不是“作为参数传递的字符串”。请参阅:docs.python.org/3/library/sys.html#sys.exc_info
Shi,

难道不是“ Exception as as:”除外吗?
亨里克

20

使用traceback.extract_stack(),如果你想模块和函数名和行号方便。

''.join(traceback.format_stack())如果只需要一个看起来像traceback.print_stack()输出的字符串,请使用。

请注意,即使''.join()你会得到一个多行字符串,因为的元素format_stack()包含\n。请参见下面的输出。

记住要import traceback

这是的输出traceback.extract_stack()。添加了格式以提高可读性。

>>> traceback.extract_stack()
[
   ('<string>', 1, '<module>', None),
   ('C:\\Python\\lib\\idlelib\\run.py', 126, 'main', 'ret = method(*args, **kwargs)'),
   ('C:\\Python\\lib\\idlelib\\run.py', 353, 'runcode', 'exec(code, self.locals)'),
   ('<pyshell#1>', 1, '<module>', None)
]

这是的输出''.join(traceback.format_stack())。添加了格式以提高可读性。

>>> ''.join(traceback.format_stack())
'  File "<string>", line 1, in <module>\n
   File "C:\\Python\\lib\\idlelib\\run.py", line 126, in main\n
       ret = method(*args, **kwargs)\n
   File "C:\\Python\\lib\\idlelib\\run.py", line 353, in runcode\n
       exec(code, self.locals)\n  File "<pyshell#2>", line 1, in <module>\n'

4

当您从异常处理程序中取出异常对象或回溯对象时要小心,因为这会导致循环引用并且gc.collect()将无法收集。在ipython / jupyter笔记本环境中,这似乎是一个特殊的问题,在该环境中无法在正确的时间清除回溯对象,甚至对gc.collect()in finallysection 的显式调用也不起作用。这就是一个很大的问题,如果您有一些大的对象因此而无法回收它们的内存(例如,没有此解决方案的CUDA内存不足异常,则需要完整的内核重新启动才能恢复)。

通常,如果要保存回溯对象,则需要从对的引用中清除它locals(),如下所示:

import sys, traceback, gc
type, val, tb = None, None, None
try:
    myfunc()
except:
    type, val, tb = sys.exc_info()
    traceback.clear_frames(tb)
# some cleanup code
gc.collect()
# and then use the tb:
if tb:
    raise type(val).with_traceback(tb)

对于jupyter notebook,您至少必须在异常处理程序中执行此操作:

try:
    myfunc()
except:
    type, val, tb = sys.exc_info()
    traceback.clear_frames(tb)
    raise type(val).with_traceback(tb)
finally:
    # cleanup code in here
    gc.collect()

经过python 3.7测试。

ps ipython或jupyter Notebook env的问题在于它具有%tb魔术功能,可以保存回溯并在以后的任何时候使用。结果locals(),参与回溯的所有帧中的任何帧都不会被释放,直到笔记本退出或另一个异常将覆盖先前存储的回溯。这是很成问题的。它不应存储没有清洗其框架的回溯。已在此处提交修订。


3

该对象可用作Exception.with_traceback()函数中的参数:

except Exception as e:
    tb = sys.exc_info()
    print(e.with_traceback(tb[2]))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.