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

Posted

技术标签:

【中文标题】如何将 traceback / sys.exc_info() 值保存在变量中?【英文标题】:How to save traceback / sys.exc_info() values in a variable? 【发布时间】:2012-01-04 12:27:24 【问题描述】:

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

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

附:我知道这可以使用 traceback 模块轻松完成,但我想在这里了解 sys.exc_info()[2] 对象的用法。

【问题讨论】:

您是否尝试打印 sys.exc_info()[x].__str__()? 您可能误解了程序中发生的事情:您所说的“sys.exc_info()[2] 对象”是回溯对象的一个​​实例(=您正在使用回溯模块已经)。现在,您可以在不使用 traceback 模块中的帮助函数的情况下操作该对象,但这并不会改变您仍在使用它的事实。 :) 所以@mac 请帮助我使用或不使用辅助函数访问此对象的值。 @dragosrsupercool - 正如我在下面的回答中提到的,您应该查看traceback documentation。我提供了一个如何以文本方式检索数据的示例,但是对象的其他方法允许您提取异常名称、代码行等……正确的方法实际上取决于您要如何操作之后的价值...... 我的answer 到另一个问题可能有助于说明细节 - 带有链接!对于固定字符串,标准库回溯模块似乎没问题。如果您想获取详细信息,请阅读源 (&lt;python install path&gt;/Lib/traceback.py) 了解更多信息。 【参考方案1】:

这就是我的做法:

>>> 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 documentation,因为您可能会发现更合适的方法,具体取决于您以后要如何处理变量...

【讨论】:

我正在寻找一种不使用回溯模块的方法。有没有办法我们可以从这个对象引用中打印回溯细节? sys.exc_info()[2] 对,这就是为什么我认为我们可以做类似 sys.exc_info()[2].format_exc() 的事情,但这不起作用.. 因此,我想知道如何从跟踪中提取价值-back 对象 sys.exc_info()[2]。有什么想法吗? sys.exc_info()[2].tb_text 给出跟随错误 -> AttributeError: 'traceback' object has no attribute 'tb_text' @dragosrsupercool - sys.exc_info()[2].tb_frame.f_code.co_names[3],但它没有任何意义......如果标准库中有一个名为traceback的模块,那是有原因的...... :) @codersofthedark traceback.format_exception(*sys.exc_info()) 是这样做的方法。但这在功能上等同于traceback.format_exc()【参考方案2】:

如果您想方便地访问模块和函数名称以及行号,请使用traceback.extract_stack()

如果您只想要一个类似于traceback.print_stack() 输出的字符串,请使用''.join(traceback.format_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'

【讨论】:

【参考方案3】:

sys.exc_info() 返回一个包含三个值(类型、值、回溯)的元组。

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

例如,在下面的程序中

try:

    a = 1/0

except Exception,e:

    exc_tuple = sys.exc_info()

现在,如果我们打印元组,值将是这个。

    exc_tuple[0] 值将是“ZeroDivisionError” exc_tuple[1] 值将是“整数除法或除以零”(作为参数传递给异常类的字符串) exc_tuple[2] 值将是“trackback object at (some memory address)

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

print str(e)

【讨论】:

对于 Python3,exc_tuple[1](又名值)是异常的 instance,而不是“作为参数传递的字符串”。见:docs.python.org/3/library/sys.html#sys.exc_info 不应该是“except Exception as e:”吗?【参考方案4】:

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

except Exception as e:
    tb = sys.exc_info()
    print(e.with_traceback(tb[2]))

【讨论】:

【参考方案5】:

从异常处理程序中取出异常对象或回溯对象时要小心,因为这会导致循环引用,gc.collect() 将无法收集。这似乎是 ipython/jupyter 笔记本环境中的一个特殊问题,其中回溯对象没有在正确的时间被清除,甚至在 finally 部分中对 gc.collect() 的显式调用也无济于事。如果您有一些巨大的对象因此无法回收其内存(例如,没有此解决方案的 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 测试。

附言ipython 或 jupyter notebook env 的问题在于它具有%tb 魔法,可以保存回溯并使其在以后的任何时候可用。因此,所有参与回溯的帧中的任何locals() 都不会被释放,直到笔记本退出或另一个异常将覆盖先前存储的回溯。这是非常有问题的。它不应该在不清理其帧的情况下存储回溯。修复提交here。

【讨论】:

以上是关于如何将 traceback / sys.exc_info() 值保存在变量中?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Ubuntu 上修复 Dataframe Python 中的 Traceback 问题

tqdm, pyyaml, traceback的使用

python traceback捕获并打印异常

python--traceback模块

[python]python中,使用traceback处理异常信息

python笔记71 - traceback.print_exc()保存异常内容