【问题标题】:How to get a complete exception stack trace in Python如何在 Python 中获取完整的异常堆栈跟踪
【发布时间】:2011-08-30 12:39:45
【问题描述】:

下面的sn-p:

import traceback

def a():
    b()

def b():
    try:
        c()
    except:
        traceback.print_exc()

def c():
    assert False

a()

产生这个输出:

Traceback (most recent call last):
  File "test.py", line 8, in b
    c()
  File "test.py", line 13, in c
    assert False
AssertionError

如果我想要完整的堆栈跟踪,包括对 a 的调用,我应该使用什么?

如果重要的话,我有 Python 2.6.6

编辑:我想获得的是相同的信息,如果我离开 try except 并让异常传播到顶层。以这个 sn-p 为例:

def a():
    b()

def b():
    c()

def c():
    assert False

a()

产生这个输出:

Traceback (most recent call last):
  File "test.py", line 10, in <module>
    a()
  File "test.py", line 2, in a
    b()
  File "test.py", line 5, in b
    c()
  File "test.py", line 8, in c
    assert False
AssertionError

【问题讨论】:

  • 我现在注意到了这个问题。我昨天answered a very similar one,这里的答案似乎很中肯。它还有一个额外的优势,它可以生成真正的回溯,您不仅可以使用traceback 函数打印,还可以将其传递给logging 模块或其他地方。

标签: python exception exception-handling traceback


【解决方案1】:

这是一个基于this answer 的函数。当不存在异常时它也可以工作:

def full_stack():
    import traceback, sys
    exc = sys.exc_info()[0]
    stack = traceback.extract_stack()[:-1]  # last one would be full_stack()
    if exc is not None:  # i.e. an exception is present
        del stack[-1]       # remove call of full_stack, the printed exception
                            # will contain the caught exception caller instead
    trc = 'Traceback (most recent call last):\n'
    stackstr = trc + ''.join(traceback.format_list(stack))
    if exc is not None:
         stackstr += '  ' + traceback.format_exc().lstrip(trc)
    return stackstr

print full_stack() 将完整的堆栈跟踪打印到顶部,包括例如IPython 的interactiveshell.py 调用,因为(据我所知)无法知道谁会捕获异常。反正这可能不值得弄清楚...

如果从except 块内调用print full_stack()full_stack 将包含向下到raise 的堆栈跟踪。在标准 Python 解释器中,这将与您在未捕获异常时收到的消息相同(这就是为什么存在 del stack[-1],您不关心 except 块,而是关心 try 块) .

【讨论】:

  • 啊,我意识到这与accepted answer 非常相似,只是它处理非except 块更清洁
  • 我稍微喜欢你的方法。对结构良好的调用堆栈进行切片比对非结构化行列表进行切片更干净。感谢 Pythonic 替代方案!
  • 优雅的解决方案!但是,我认为您在滥用lstrip(),因为它会删除trc 中的任何字符,这可能会导致意外的截断堆栈。例如,首选方式是if stackstr.startswith(trc): stackstr = stackstr.replace(trc, '', 1)
  • @Delgan 谢谢,好点子 - 虽然因为exc is not None 我猜一个人甚至可以只有stackstr += ' ' + traceback.format_exc()[len(trc):],因为它总是以trc 开头。
【解决方案2】:

我不知道是否有更好的方法,但这是我所做的:

import traceback
import sys

def format_exception(e):
    exception_list = traceback.format_stack()
    exception_list = exception_list[:-2]
    exception_list.extend(traceback.format_tb(sys.exc_info()[2]))
    exception_list.extend(traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1]))

    exception_str = "Traceback (most recent call last):\n"
    exception_str += "".join(exception_list)
    # Removing the last \n
    exception_str = exception_str[:-1]

    return exception_str

def main1():
    main2()

def main2():
    try:
        main3()
    except Exception as e:
        print "Printing only the traceback above the current stack frame"
        print "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
        print
        print "Printing the full traceback as if we had not caught it here..."
        print format_exception(e)

def main3():
    raise Exception()

if __name__ == '__main__':
    main1()

这是我得到的输出:

Printing only the traceback above the current stack frame
Traceback (most recent call last):
  File "exc.py", line 22, in main2
    main3()
  File "exc.py", line 31, in main3
    raise Exception()
Exception


Printing the full traceback as if we had not caught it here...
Traceback (most recent call last):
  File "exc.py", line 34, in <module>
    main1()
  File "exc.py", line 18, in main1
    main2()
  File "exc.py", line 22, in main2
    main3()
  File "exc.py", line 31, in main3
    raise Exception()
Exception

【讨论】:

  • 我接受这个,因为它是真正解决问题的唯一答案。但是我仍然很遗憾没有图书馆对此进行调用。
  • +1 - 我发布了一个similar answer,它也适用于except
【解决方案3】:

使用

 traceback.print_stack()

http://docs.python.org/library/traceback.html#traceback.print_stack

suxmac2 $ python out.py 
  File "out.py", line 16, in <module>
    a()
  File "out.py", line 5, in a
    b()
  File "out.py", line 11, in b
    traceback.print_stack()

【讨论】:

  • 这样就提供了另一半,有没有办法把整个东西变成一个整体?
  • 稍后调用您的自己的代码...没有人会阻止您自己调用 print_stack() 和 print_exc() - 或者?
  • traceback.print_exception(*sys.exc_info())
  • @Keith 效果和traceback.print_exc()一样
  • 我可以同时调用它们并合并输出,但标准库似乎不太可能已经涵盖了这一点,本质上我只想要如果我让异常传播到顶层
【解决方案4】:


这是Tobias Kienzler answer 的一个更好的变体。它的工作原理相同,但不能在 except 块中调用,而是在更深的地方调用。 换句话说,这个变体将打印相同的堆栈,当被调用时

try:
   ...
except Exception:
    print full_stack()

def print_full_stack():
    print full_stack()

try:
   ...
except Exception:
    print_full_stack()

代码如下:

def full_stack():
    import traceback, sys
    exc = sys.exc_info()[0]
    if exc is not None:
        f = sys.exc_info()[-1].tb_frame.f_back
        stack = traceback.extract_stack(f)
    else:
        stack = traceback.extract_stack()[:-1]  # last one would be full_stack()
    trc = 'Traceback (most recent call last):\n'
    stackstr = trc + ''.join(traceback.format_list(stack))
    if exc is not None:
        stackstr += '  ' + traceback.format_exc().lstrip(trc)
    return stackstr

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-08
    • 2011-05-15
    • 1970-01-01
    • 1970-01-01
    • 2015-05-14
    • 2013-04-08
    • 2020-01-27
    • 2015-10-03
    相关资源
    最近更新 更多