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

cod*_*ark 111 python exception-handling

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

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]
Run Code Online (Sandbox Code Playgroud)

输出:

0 <type 'exceptions.NameError'>
1 
2 <traceback object at 0xbd5fc8>
Run Code Online (Sandbox Code Playgroud)

期望的输出:

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

PS我知道这可以使用traceback模块轻松完成,但我想知道sys.exc_info()[2]对象的用法.

mac*_*mac 160

我是这样做的:

>>> 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'
Run Code Online (Sandbox Code Playgroud)

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

  • @dragosrsupercool - `sys.exc_info()[2] .tb_frame.f_code.co_names [3]`,但它没有任何意义......如果标准库中有一个名为`traceback`的模块,那就有一个原因为了它... :) (3认同)
  • @codersofthedark `traceback.format_exception(*sys.exc_info())` 是这样做的方法。但这在功能上等同于 `traceback.format_exc()`。 (2认同)

key*_*eya 22

sys.exc_info()返回一个包含三个值(类型,值,跟踪)的元组.

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

例如,在以下程序中

try:

    a = 1/0

except Exception,e:

    exc_tuple = sys.exc_info()
Run Code Online (Sandbox Code Playgroud)

现在,如果我们打印元组,那么值就是这个.

  1. exc_tuple [0]值为" ZeroDivisionError "
  2. exc_tuple [1]值将是" 整数除法或模数为零 "(作为参数传递给异常类的字符串)
  3. exc_tuple [2]的值将是" 某个内存地址处的trackback对象 "

只需以字符串格式打印异常,即可获取上述详细信息.

print str(e)
Run Code Online (Sandbox Code Playgroud)

  • 不应该是“除了 Exception as e:”吗? (3认同)

Nat*_*han 17

使用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)
]
Run Code Online (Sandbox Code Playgroud)

这是来自的输出''.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'
Run Code Online (Sandbox Code Playgroud)


sta*_*son 8

从异常处理程序中取出异常对象或回溯对象时要小心,因为这会导致循环引用并且gc.collect()无法收集。这似乎是 ipython/jupyter notebook 环境中的一个特殊问题,其中回溯对象没有在正确的时间被清除,甚至对gc.collect()infinally部分的显式调用也没有任何作用。如果您有一些巨大的对象因此无法回收它们的内存(例如,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)
Run Code Online (Sandbox Code Playgroud)

对于 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()
Run Code Online (Sandbox Code Playgroud)

用python 3.7测试。

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