从异常对象中提取回溯信息 [英] Extract traceback info from an exception object

查看:29
本文介绍了从异常对象中提取回溯信息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定一个异常对象(来源不明)有没有办法获得它的回溯?我有这样的代码:

def 东西():尝试:.....返回有用除了作为 e 的例外:返回 e结果 = 东西()如果是实例(结果,异常):result.traceback <-- 如何?

一旦我拥有它,我如何从 Exception 对象中提取回溯?

解决方案

这个问题的答案取决于您使用的 Python 版本.

在 Python 3 中

很简单:异常配备了包含回溯的 __traceback__ 属性.这个属性也是可写的,可以使用异常的with_traceback方法方便的设置:

raise Exception("foo发生").with_traceback(tracebackobj)

这些功能作为 raise 文档.

这部分答案的所有功劳都归功于 Vyctor,他首先发布了此信息.我把它包括在这里只是因为这个答案被卡在了顶部,而且 Python 3 变得越来越普遍.

在 Python 2 中

这很烦人的复杂.回溯的问题在于它们引用了堆栈帧,而堆栈帧引用了引用堆栈帧的回溯 引用... 你懂的.这会导致垃圾收集器出现问题.(感谢 ecatmur 首先指出这一点.)

解决这个问题的好方法是手术打破循环 在离开 except 子句之后,这是 Python 3 所做的.Python 2 解决方案要丑得多:您提供了一个临时功能,sys.exc_info(),它只在 except 子句内有效.它返回一个包含异常、异常类型和当前正在处理的任何异常的回溯的元组.

因此,如果您在 except 子句中,您可以使用 sys.exc_info() 的输出以及 traceback 模块来做各种有用的事情:

<预><代码>>>>导入系统,回溯>>>def raise_exception():... 尝试:...引发异常...除了例外:... ex_type, ex, tb = sys.exc_info()... traceback.print_tb(tb)... 最后:... del tb...>>>raise_exception()文件<stdin>",第 3 行,在 raise_exception 中

但正如您的编辑所表明的那样,如果您的异常尚未被处理,则您正在尝试获取 打印的回溯,在它已经被处理之后.这是一个更难的问题.不幸的是,sys.exc_info 在没有处理异常时返回 (None, None, None).其他相关的 sys 属性也无济于事.sys.exc_traceback 在没有处理异常时被弃用和未定义;sys.last_traceback 看起来很完美,但它似乎只能在交互式会话中定义.

如果您可以控制引发异常的方式,您可以使用 inspect自定义异常存储一些信息.但我不完全确定这将如何运作.

说实话,捕获并返回异常是一件很不寻常的事情.这可能表明您无论如何都需要重构.

Given an Exception object (of unknown origin) is there way to obtain its traceback? I have code like this:

def stuff():
   try:
       .....
       return useful
   except Exception as e:
       return e

result = stuff()
if isinstance(result, Exception):
    result.traceback <-- How?

How can I extract the traceback from the Exception object once I have it?

解决方案

The answer to this question depends on the version of Python you're using.

In Python 3

It's simple: exceptions come equipped with a __traceback__ attribute that contains the traceback. This attribute is also writable, and can be conveniently set using the with_traceback method of exceptions:

raise Exception("foo occurred").with_traceback(tracebackobj)

These features are minimally described as part of the raise documentation.

All credit for this part of the answer should go to Vyctor, who first posted this information. I'm including it here only because this answer is stuck at the top, and Python 3 is becoming more common.

In Python 2

It's annoyingly complex. The trouble with tracebacks is that they have references to stack frames, and stack frames have references to the tracebacks that have references to stack frames that have references to... you get the idea. This causes problems for the garbage collector. (Thanks to ecatmur for first pointing this out.)

The nice way of solving this would be to surgically break the cycle after leaving the except clause, which is what Python 3 does. The Python 2 solution is much uglier: you are provided with an ad-hoc function,sys.exc_info(), which only works inside the except clause. It returns a tuple containing the exception, the exception type, and the traceback for whatever exception is currently being handled.

So if you are inside the except clause, you can use the output of sys.exc_info() along with the traceback module to do various useful things:

>>> import sys, traceback
>>> def raise_exception():
...     try:
...         raise Exception
...     except Exception:
...         ex_type, ex, tb = sys.exc_info()
...         traceback.print_tb(tb)
...     finally:
...         del tb
... 
>>> raise_exception()
  File "<stdin>", line 3, in raise_exception

But as your edit indicates, you're trying to get the traceback that would have been printed if your exception had not been handled, after it has already been handled. That's a much harder question. Unfortunately, sys.exc_info returns (None, None, None) when no exception is being handled. Other related sys attributes don't help either. sys.exc_traceback is deprecated and undefined when no exception is being handled; sys.last_traceback seems perfect, but it appears only to be defined during interactive sessions.

If you can control how the exception is raised, you might be able to use inspect and a custom exception to store some of the information. But I'm not entirely sure how that would work.

To tell the truth, catching and returning an exception is kind of an unusual thing to do. This might be a sign that you need to refactor anyway.

这篇关于从异常对象中提取回溯信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆