这个问题的答案取决于您使用的 Python 版本。
在 Python 3 中
很简单:异常带有一个包含回溯的__traceback__ 属性。该属性也是可写的,可以使用异常的with_traceback方法方便地设置:
raise Exception("foo occurred").with_traceback(tracebackobj)
raise 文档中对这些功能进行了最低限度的描述。
这部分答案的所有功劳都应归功于first posted this information 的维克多。我将它包括在这里只是因为这个答案停留在顶部,并且 Python 3 变得越来越普遍。
在 Python 2 中
这非常复杂。回溯的问题在于它们引用了堆栈帧,而堆栈帧引用了引用堆栈帧that have references to... 的回溯,你明白了。这会导致垃圾收集器出现问题。 (感谢ecatmur 首先指出这一点。)
解决这个问题的好方法是在离开except 子句之后手术式地break the cycle,这是Python 3 所做的。 Python 2 的解决方案更加丑陋:为您提供了一个 ad-hoc 函数sys.exc_info(),它只能在 except 子句 中工作。它返回一个元组,其中包含异常、异常类型和当前正在处理的任何异常的回溯。
因此,如果您在 except 子句中,则可以使用 sys.exc_info() 的输出以及 traceback 模块来做各种有用的事情:
>>> 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
但正如您的编辑所表明的那样,如果您的异常没有得到处理,您正在尝试获取 已经被打印的回溯,在它已经已经被处理之后.这是一个更难的问题。不幸的是,sys.exc_info 在没有处理异常时返回(None, None, None)。其他相关的sys 属性也无济于事。 sys.exc_traceback 在未处理异常时已弃用且未定义; sys.last_traceback 看起来很完美,但似乎只能在交互式会话期间定义。
如果您可以控制引发异常的方式,则可以使用inspect 和custom exception 来存储一些信息。但我不完全确定它会如何工作。
说实话,捕获并返回异常是一件不寻常的事情。这可能表明您无论如何都需要重构。