如何在Python中获取完整的异常堆栈跟踪

44 投票
4 回答
41298 浏览
提问于 2025-04-16 18:07

以下这段代码:

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,让错误直接抛到最上层时得到的信息。这段代码举个例子:

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

4 个回答

12

使用

 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()
38

这里有一个函数,基于这个答案。即使没有异常发生,它也能正常工作:

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会显示从异常抛出到捕获的整个调用栈。在标准的Python解释器中,这个信息和你在没有捕获异常时收到的消息是一样的(这就是为什么有del stack[-1]这行代码,因为你不关心except块的内容,而是try块的内容)。

26

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

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

撰写回答