Python 从异常对象提取回溯信息
给定一个异常对象(来源未知),是否有方法获取其回溯?我有这样的代码:Python 从异常对象提取回溯信息,python,debugging,exception-handling,Python,Debugging,Exception Handling,给定一个异常对象(来源未知),是否有方法获取其回溯?我有这样的代码: def stuff(): try: ..... return useful except Exception as e: return e result = stuff() if isinstance(result, Exception): result.traceback <-- How? def stuff(): 尝试: ..... 返回有用的 例外情
def stuff():
try:
.....
return useful
except Exception as e:
return e
result = stuff()
if isinstance(result, Exception):
result.traceback <-- How?
def stuff():
尝试:
.....
返回有用的
例外情况除外,如e:
返回e
结果=stuff()
如果存在(结果、异常):
result.traceback这个问题的答案取决于您使用的Python版本
在Python 3中
很简单:异常带有一个包含回溯的\uuuuuuuuuuuuuu
属性。此属性也是可写的,可以使用异常的with_traceback
方法方便地设置:
raise Exception("foo occurred").with_traceback(tracebackobj)
这些特性作为文档的一部分进行了最低限度的描述
答案的这一部分应该归功于维克托,他是谁。我把它包括在这里只是因为这个答案停留在顶部,而Python 3正变得越来越普遍
在Python 2中
复杂得令人烦恼。回溯的问题在于,它们引用了堆栈帧,堆栈帧引用了回溯,而回溯引用了堆栈帧。这会导致垃圾收集器出现问题。(感谢您首先指出这一点。)
解决这个问题的好方法是在离开except
子句后进行手术,这是Python3所做的。Python2的解决方案要难看得多:提供了一个特殊函数,它只在子句中起作用,而不在子句中起作用。它返回一个元组,其中包含异常、异常类型以及当前正在处理的任何异常的回溯
因此,如果您在except
子句中,可以使用sys.exc_info()
的输出以及模块来执行各种有用的操作:
>>> 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
导入系统,回溯
>>>def raise_异常():
... 尝试:
... 引发异常
... 除例外情况外:
... ex_type,ex,tb=sys.exc_info()
... 回溯打印tb(tb)
... 最后:
... 德尔结核
...
>>>引发异常()
文件“”,第3行,在raise\u异常中
但是,正如您的编辑所指出的,您正在尝试在异常已经处理之后,获取如果您的异常未被处理,则会打印的回溯。这是一个更难的问题。不幸的是,sys.exc_info
在未处理异常时返回(无,无,无)
。其他相关的sys
属性也没有帮助sys.exc_traceback
在未处理异常时已弃用且未定义sys.last_traceback
看起来很完美,但它似乎只在交互式会话中定义
如果可以控制异常的引发方式,则可以使用和来存储一些信息。但我不完全确定这将如何运作
说实话,捕获并返回异常是一件不寻常的事情。这可能是您无论如何都需要重构的一个迹象。有一个很好的理由,回溯不存储在异常中;因为回溯持有对其堆栈局部变量的引用,这将导致循环引用和(临时)内存泄漏,直到循环GC启动。(这就是你应该这样做的原因。)
我能想到的唯一一件事就是让你去monkeypatch填充
的全局变量,这样当它认为它在捕获异常
时,它实际上是在捕获一个特殊类型,异常作为调用方传播给你:
module_containing_stuff.Exception = type("BogusException", (Exception,), {})
try:
stuff()
except Exception:
import sys
print sys.exc_info()
由于内置类有一个\uuuu traceback\uuu
属性,该属性包含一个回溯对象(使用Python 3.2.3):
>>试试:
... 引发异常()
... 例外情况除外,如e:
... tb=e.\u回溯__
...
>>>结核病
问题是,过了一段时间后,我只找到了几篇文章,但没有一篇文章描述了您是否应该(或为什么不)使用\uuuuuuu traceback\uuuu
然而,报告说:
当引发异常并将其作为\uu traceback\uuu
属性附加到该异常时,通常会自动创建回溯对象,该属性是可写的
因此,我假设它是要被使用的。一种从Python 3中的异常对象获取字符串回溯的方法:
import traceback
# `e` is an exception object that you get from somewhere
traceback_str = ''.join(traceback.format_tb(e.__traceback__))
traceback.format_tb(…)
返回字符串列表<代码>''。连接(…)
将它们连接在一起。有关更多参考信息,请访问:作为旁白,如果您希望实际获得打印到终端的完整回溯,您需要:
>>> try:
... print(1/0)
... except Exception as e:
... exc = e
...
>>> exc
ZeroDivisionError('division by zero')
>>> tb_str = traceback.format_exception(etype=type(exc), value=exc, tb=exc.__traceback__)
>>> tb_str
['Traceback (most recent call last):\n', ' File "<stdin>", line 2, in <module>\n', 'ZeroDivisionError: division by zero\n']
>>> print("".join(tb_str))
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero
您可以使用返回str
或打印到标准输出
import traceback
try:
b"x81".decode()
except UnicodeError:
traceback.print_exc() # prints to stdout
my_traceback = traceback.format_exc() # returns a str
print(my_traceback)
import traceback
try:
b"x81".decode()
except UnicodeError as exc:
# etype is inferred from `value` since python3.5 so no need to pass a value...
# format_exception returns a list
my_traceback = "".join(traceback.format_exception(etype=None, value=exc, tb=exc.__traceback__))
traceback.print_exception(etype=None, value=exc, tb=exc.__traceback__)
如果您需要从实际的异常中获取它(尽管我不明白为什么)
返回一个str
打印到标准输出
import traceback
try:
b"x81".decode()
except UnicodeError:
traceback.print_exc() # prints to stdout
my_traceback = traceback.format_exc() # returns a str
print(my_traceback)
import traceback
try:
b"x81".decode()
except UnicodeError as exc:
# etype is inferred from `value` since python3.5 so no need to pass a value...
# format_exception returns a list
my_traceback = "".join(traceback.format_exception(etype=None, value=exc, tb=exc.__traceback__))
traceback.print_exception(etype=None, value=exc, tb=exc.__traceback__)
小心
不要存储对\uuu traceback\uuu
(或exc
)的引用以供以后使用,因为回溯对象包含对所有堆栈帧对象的引用,这些对象包括调用堆栈,每个堆栈帧包含对其所有局部变量的引用。因此,可从回溯对象访问的对象的传递闭包的大小可能非常大。如果维护该引用,这些对象将不会被垃圾收集。更愿意将回溯呈现为另一种形式,以便在内存中进行短期存储。”
罗伯特Simulthy- Python超越基本- 11例外和错误- Traceback对象< /P>我同意返回异常是某种非常规的,但看到一些背后的理论基础。@ THG435,好,这是更有意义的。请考虑我的上述解决方案使用<代码> sys。ExcIfnIs<代码>结合我建议您的O另一个问题。关于回溯对象的更多信息(几乎没有):这是错误的。Python 3确实将回溯对象置于异常状态,如
e.。\uuuu traceback\uuuuu
@GlennMaynard Python 3通过在退出时删除异常目标来解决此问题