traceback — 打印或检索栈回溯

源代码: Lib/traceback.py


此模块提供了用于提取、格式化和打印 Python 程序栈跟踪的标准接口。它比解释器的默认回溯显示更灵活,因此可以配置输出的某些方面。最后,它包含一个实用工具,用于捕获有关异常的足够信息以便以后打印,而无需保存对实际异常的引用。由于异常可能是大型对象图的根,因此此实用工具可以显著改善内存管理。

该模块使用回溯对象——这些是 types.TracebackType 类型的对象,它们被分配给 BaseException 实例的 __traceback__ 字段。

参见

模块 faulthandler

用于在故障、超时或用户信号时显式转储 Python 回溯。

模块 pdb

Python 程序的交互式源代码调试器。

模块的 API 可分为两部分

  • 提供基本功能的模块级函数,这些函数对于交互式检查异常和回溯非常有用。

  • TracebackException 类及其辅助类 StackSummaryFrameSummary。它们提供更大的输出灵活性,并且能够存储必要的信息以便稍后格式化,而无需持有对实际异常和回溯对象的引用。

3.13 版本新增: 输出默认着色,并且可以通过环境变量控制

模块级函数

traceback.print_tb(tb, limit=None, file=None)

回溯对象 tb 中打印最多 limit 个栈跟踪条目(从调用者帧开始),如果 limit 为正。否则,打印最后 abs(limit) 个条目。如果 limit 被省略或为 None,则打印所有条目。如果 file 被省略或为 None,输出将发送到 sys.stderr;否则它应该是一个打开的文件类文件对象以接收输出。

备注

limit 参数的含义与 sys.tracebacklimit 的含义不同。负的 limit 值对应于正的 sys.tracebacklimit 值,而正的 limit 值的行为无法通过 sys.tracebacklimit 实现。

3.5 版本中有所改变: 添加了负 limit 支持。

traceback.print_exception(exc, /, [value, tb, ]limit=None, file=None, chain=True)

将异常信息和从 回溯对象 tb 中提取的栈跟踪条目打印到 file。这与 print_tb() 不同,区别如下:

  • 如果 tb 不是 None,它会打印一个标题 Traceback (most recent call last):

  • 它会在栈跟踪之后打印异常类型和 value

  • 如果 type(value)SyntaxError 并且 value 具有适当的格式,它会打印发生语法错误的行,并用一个插入符号指示错误的近似位置。

自 Python 3.10 起,可以不传递 valuetb,而是将一个异常对象作为第一个参数传递。如果提供了 valuetb,则第一个参数将被忽略以保持向后兼容性。

可选的 limit 参数与 print_tb() 的含义相同。如果 chain 为 true(默认值),则链式异常(异常的 __cause____context__ 属性)也将被打印,就像解释器本身在打印未处理的异常时所做的那样。

3.5 版本中有所改变: etype 参数被忽略,并从 value 的类型推断。

3.10 版本中有所改变: etype 参数已重命名为 exc,现在是仅位置参数。

traceback.print_exc(limit=None, file=None, chain=True)

这是 print_exception(sys.exception(), limit=limit, file=file, chain=chain) 的简写。

traceback.print_last(limit=None, file=None, chain=True)

这是 print_exception(sys.last_exc, limit=limit, file=file, chain=chain) 的简写。通常,它只在异常到达交互式提示符后才起作用(参见 sys.last_exc)。

traceback.print_stack(f=None, limit=None, file=None)

如果 limit 为正,则打印最多 limit 个栈跟踪条目(从调用点开始)。否则,打印最后 abs(limit) 个条目。如果 limit 被省略或为 None,则打印所有条目。可选的 f 参数可用于指定要开始的替代 栈帧。可选的 file 参数与 print_tb() 的含义相同。

3.5 版本中有所改变: 添加了负 limit 支持。

traceback.extract_tb(tb, limit=None)

返回一个 StackSummary 对象,表示从 回溯对象 tb 中提取的“预处理”栈跟踪条目列表。它对于替代栈跟踪格式化很有用。可选的 limit 参数与 print_tb() 的含义相同。“预处理”栈跟踪条目是一个 FrameSummary 对象,包含 filenamelinenonameline 属性,这些属性表示通常为栈跟踪打印的信息。

traceback.extract_stack(f=None, limit=None)

从当前 栈帧 中提取原始回溯。返回值与 extract_tb() 具有相同的格式。可选的 flimit 参数与 print_stack() 的含义相同。

traceback.print_list(extracted_list, file=None)

extract_tb()extract_stack() 返回的元组列表作为格式化的栈跟踪打印到给定文件。如果 fileNone,则输出写入 sys.stderr

traceback.format_list(extracted_list)

给定一个由 extract_tb()extract_stack() 返回的元组列表或 FrameSummary 对象列表,返回一个准备好打印的字符串列表。结果列表中的每个字符串对应于参数列表中相同索引的项。每个字符串以换行符结尾;对于那些源文本行不为 None 的项,字符串中也可能包含内部换行符。

traceback.format_exception_only(exc, /, [value, ]*, show_group=False)

使用异常值(例如由 sys.last_value 给出的值)格式化回溯的异常部分。返回值是一个字符串列表,每个字符串以换行符结尾。列表包含异常消息,通常是一个字符串;但是,对于 SyntaxError 异常,它包含多行(打印时)显示有关语法错误发生位置的详细信息。消息之后,列表包含异常的 notes

自 Python 3.10 起,可以不传递 value,而是将一个异常对象作为第一个参数传递。如果提供了 value,则第一个参数将被忽略以保持向后兼容性。

show_groupTrue 且异常是 BaseExceptionGroup 的实例时,嵌套异常也将递归包含在内,并相对于其嵌套深度进行缩进。

3.10 版本中有所改变: etype 参数已重命名为 exc,现在是仅位置参数。

3.11 版本中有所改变: 返回列表现在包含附加到异常的任何 notes

3.13 版本中有所改变: 添加了 show_group 参数。

traceback.format_exception(exc, /, [value, tb, ]limit=None, chain=True)

格式化栈跟踪和异常信息。参数的含义与 print_exception() 的相应参数相同。返回值是一个字符串列表,每个字符串以换行符结尾,有些字符串包含内部换行符。当这些行连接并打印时,打印的文本与 print_exception() 打印的完全相同。

3.5 版本中有所改变: etype 参数被忽略,并从 value 的类型推断。

3.10 版本中有所改变: 此函数的行为和签名已修改为与 print_exception() 匹配。

traceback.format_exc(limit=None, chain=True)

这类似于 print_exc(limit),但返回一个字符串而不是打印到文件。

traceback.format_tb(tb, limit=None)

这是 format_list(extract_tb(tb, limit)) 的简写。

traceback.format_stack(f=None, limit=None)

这是 format_list(extract_stack(f, limit)) 的简写。

traceback.clear_frames(tb)

通过调用每个 帧对象clear() 方法,清除 回溯 tb 中所有栈帧的局部变量。

在 3.4 版本加入。

traceback.walk_stack(f)

从给定帧开始,按照 f.f_back 遍历栈,为每个帧生成帧和行号。如果 fNone,则使用当前栈。此辅助函数与 StackSummary.extract() 一起使用。

在 3.5 版本加入。

3.14 版本中有所改变: 此函数以前返回一个生成器,该生成器在首次迭代时会遍历栈。现在返回的生成器是调用 walk_stack 时的栈状态。

traceback.walk_tb(tb)

按照 tb_next 遍历回溯,为每个帧生成帧和行号。此辅助函数与 StackSummary.extract() 一起使用。

在 3.5 版本加入。

TracebackException 对象

在 3.5 版本加入。

TracebackException 对象是从实际异常创建的,用于捕获数据以便稍后打印。它们通过避免持有对 回溯 对象的引用,提供了一种更轻量级的方式来存储此信息。此外,与上述模块级函数相比,它们提供了更多选项来配置输出。

class traceback.TracebackException(exc_type, exc_value, exc_traceback, *, limit=None, lookup_lines=True, capture_locals=False, compact=False, max_group_width=15, max_group_depth=10)

捕获异常以供稍后渲染。limitlookup_linescapture_locals 的含义与 StackSummary 类相同。

如果 compact 为 true,则只有 TracebackExceptionformat() 方法所需的数据才会保存在类属性中。特别是,只有当 __cause__None__suppress_context__ 为 false 时,才会计算 __context__ 字段。

请注意,当捕获局部变量时,它们也会显示在回溯中。

max_group_widthmax_group_depth 控制异常组的格式(参见 BaseExceptionGroup)。深度指的是组的嵌套级别,宽度指的是单个异常组的异常数组大小。当任何一个限制被超出时,格式化输出将被截断。

3.10 版本中有所改变: 添加了 compact 参数。

3.11 版本中有所改变: 添加了 max_group_widthmax_group_depth 参数。

__cause__

原始 __cause__TracebackException

__context__

原始 __context__TracebackException

exceptions

如果 self 表示一个 ExceptionGroup,则此字段包含一个 TracebackException 实例列表,表示嵌套异常。否则为 None

在 3.11 版本中新增。

__suppress_context__

原始异常的 __suppress_context__ 值。

__notes__

原始异常的 __notes__ 值,如果异常没有任何备注,则为 None。如果它不为 None,则在异常字符串之后以回溯格式化。

在 3.11 版本中新增。

stack

表示回溯的 StackSummary

exc_type

原始回溯的类。

3.13 版本弃用。

exc_type_str

原始异常类的字符串显示。

在 3.13 版本加入。

filename

对于语法错误 - 发生错误的文件名。

lineno

对于语法错误 - 发生错误的行号。

end_lineno

对于语法错误 - 发生错误的结束行号。如果不存在,可以为 None

在 3.10 版本加入。

text

对于语法错误 - 发生错误的文本。

offset

对于语法错误 - 错误在文本中的偏移量。

end_offset

对于语法错误 - 错误在文本中的结束偏移量。如果不存在,可以为 None

在 3.10 版本加入。

msg

对于语法错误 - 编译器错误消息。

classmethod from_exception(exc, *, limit=None, lookup_lines=True, capture_locals=False)

捕获异常以供稍后渲染。limitlookup_linescapture_locals 的含义与 StackSummary 类相同。

请注意,当捕获局部变量时,它们也会显示在回溯中。

print(*, file=None, chain=True)

format() 返回的异常信息打印到 file(默认为 sys.stderr)。

在 3.11 版本中新增。

format(*, chain=True)

格式化异常。

如果 chain 不为 True,则 __cause____context__ 将不会被格式化。

返回值是一个字符串生成器,每个字符串以换行符结尾,有些字符串包含内部换行符。print_exception() 是此方法的包装器,它只是将这些行打印到文件。

format_exception_only(*, show_group=False)

格式化回溯的异常部分。

返回值是一个字符串生成器,每个字符串以换行符结尾。

show_groupFalse 时,生成器会发出异常消息,然后是其注释(如果有的话)。异常消息通常是一个字符串;但是,对于 SyntaxError 异常,它由多行组成,这些行(打印时)显示有关语法错误发生位置的详细信息。

show_groupTrue 且异常是 BaseExceptionGroup 的实例时,嵌套异常也将递归包含在内,并相对于其嵌套深度进行缩进。

3.11 版本中有所改变: 异常的 notes 现在包含在输出中。

3.13 版本中有所改变: 添加了 show_group 参数。

StackSummary 对象

在 3.5 版本加入。

StackSummary 对象表示准备好格式化的调用栈。

class traceback.StackSummary
classmethod extract(frame_gen, *, limit=None, lookup_lines=True, capture_locals=False)

从帧生成器(例如 walk_stack()walk_tb() 返回的生成器)构造一个 StackSummary 对象。

如果提供了 limit,则只从 frame_gen 中获取这么多帧。如果 lookup_linesFalse,则返回的 FrameSummary 对象将尚未读取其行,从而使创建 StackSummary 的成本更低(如果它可能不会实际格式化,这可能很有价值)。如果 capture_localsTrue,则每个 FrameSummary 中的局部变量将作为对象表示形式捕获。

3.12 版本中有所改变: 从局部变量上的 repr() 引起的异常(当 capture_localsTrue 时)不再传播给调用者。

classmethod from_list(a_list)

从提供的 FrameSummary 对象列表或旧式元组列表构造一个 StackSummary 对象。每个元组都应该是一个四元组,其中包含 filenamelinenonameline 作为元素。

format()

返回一个准备好打印的字符串列表。结果列表中的每个字符串对应于栈中的单个 。每个字符串以换行符结尾;字符串中也可能包含内部换行符,用于那些包含源代码行的项。

对于相同帧和行的长序列,会显示前几次重复,然后是总结行,说明后续重复的确切次数。

3.6 版本中有所改变: 重复帧的长序列现在会缩写。

format_frame_summary(frame_summary)

返回一个字符串,用于打印栈中涉及的 中的一个。此方法由 StackSummary.format() 为每个要打印的 FrameSummary 对象调用。如果它返回 None,则该帧将从输出中省略。

在 3.11 版本中新增。

FrameSummary 对象

在 3.5 版本加入。

一个 FrameSummary 对象表示 回溯 中的单个

class traceback.FrameSummary(filename, lineno, name, *, lookup_line=True, locals=None, line=None, end_lineno=None, colno=None, end_colno=None)

表示正在格式化或打印的 回溯 或栈中的单个 。它可能可选地包含帧局部变量的字符串化版本。如果 lookup_lineFalse,则在访问 FrameSummaryline 属性(这在将其转换为 tuple 时也会发生)之前,不会查找源代码。可以直接提供 line,这将完全阻止行查找。locals 是一个可选的局部变量映射,如果提供,变量表示将存储在摘要中以供以后显示。

FrameSummary 实例具有以下属性

filename

此帧源代码的文件名。等同于访问 帧对象 f 上的 f.f_code.co_filename

lineno

此帧源代码的行号。

name

等同于访问 帧对象 f 上的 f.f_code.co_name

line

表示此帧源代码的字符串,已去除前导和尾随空格。如果源代码不可用,则为 None

end_lineno

此帧源代码的最后一行号。默认情况下,它设置为 lineno,并且索引从 1 开始。

3.13 版本中有所改变: 默认值从 None 更改为 lineno

colno

此帧源代码的列号。默认情况下,它为 None,并且索引从 0 开始。

end_colno

此帧源代码的最后一列号。默认情况下,它为 None,并且索引从 0 开始。

使用模块级函数的示例

这个简单的示例实现了一个基本的读-求值-打印循环,类似于(但不如)标准 Python 交互式解释器循环。有关解释器循环的更完整实现,请参阅 code 模块。

import sys, traceback

def run_user_code(envdir):
    source = input(">>> ")
    try:
        exec(source, envdir)
    except Exception:
        print("Exception in user code:")
        print("-"*60)
        traceback.print_exc(file=sys.stdout)
        print("-"*60)

envdir = {}
while True:
    run_user_code(envdir)

以下示例演示了打印和格式化异常和回溯的不同方式

import sys, traceback

def lumberjack():
    bright_side_of_life()

def bright_side_of_life():
    return tuple()[0]

try:
    lumberjack()
except IndexError as exc:
    print("*** print_tb:")
    traceback.print_tb(exc.__traceback__, limit=1, file=sys.stdout)
    print("*** print_exception:")
    traceback.print_exception(exc, limit=2, file=sys.stdout)
    print("*** print_exc:")
    traceback.print_exc(limit=2, file=sys.stdout)
    print("*** format_exc, first and last line:")
    formatted_lines = traceback.format_exc().splitlines()
    print(formatted_lines[0])
    print(formatted_lines[-1])
    print("*** format_exception:")
    print(repr(traceback.format_exception(exc)))
    print("*** extract_tb:")
    print(repr(traceback.extract_tb(exc.__traceback__)))
    print("*** format_tb:")
    print(repr(traceback.format_tb(exc.__traceback__)))
    print("*** tb_lineno:", exc.__traceback__.tb_lineno)

该示例的输出将类似于这样

*** print_tb:
  File "<doctest...>", line 10, in <module>
    lumberjack()
    ~~~~~~~~~~^^
*** print_exception:
Traceback (most recent call last):
  File "<doctest...>", line 10, in <module>
    lumberjack()
    ~~~~~~~~~~^^
  File "<doctest...>", line 4, in lumberjack
    bright_side_of_life()
    ~~~~~~~~~~~~~~~~~~~^^
IndexError: tuple index out of range
*** print_exc:
Traceback (most recent call last):
  File "<doctest...>", line 10, in <module>
    lumberjack()
    ~~~~~~~~~~^^
  File "<doctest...>", line 4, in lumberjack
    bright_side_of_life()
    ~~~~~~~~~~~~~~~~~~~^^
IndexError: tuple index out of range
*** format_exc, first and last line:
Traceback (most recent call last):
IndexError: tuple index out of range
*** format_exception:
['Traceback (most recent call last):\n',
 '  File "<doctest default[0]>", line 10, in <module>\n    lumberjack()\n    ~~~~~~~~~~^^\n',
 '  File "<doctest default[0]>", line 4, in lumberjack\n    bright_side_of_life()\n    ~~~~~~~~~~~~~~~~~~~^^\n',
 '  File "<doctest default[0]>", line 7, in bright_side_of_life\n    return tuple()[0]\n           ~~~~~~~^^^\n',
 'IndexError: tuple index out of range\n']
*** extract_tb:
[<FrameSummary file <doctest...>, line 10 in <module>>,
 <FrameSummary file <doctest...>, line 4 in lumberjack>,
 <FrameSummary file <doctest...>, line 7 in bright_side_of_life>]
*** format_tb:
['  File "<doctest default[0]>", line 10, in <module>\n    lumberjack()\n    ~~~~~~~~~~^^\n',
 '  File "<doctest default[0]>", line 4, in lumberjack\n    bright_side_of_life()\n    ~~~~~~~~~~~~~~~~~~~^^\n',
 '  File "<doctest default[0]>", line 7, in bright_side_of_life\n    return tuple()[0]\n           ~~~~~~~^^^\n']
*** tb_lineno: 10

以下示例显示了打印和格式化栈的不同方式

>>> import traceback
>>> def another_function():
...     lumberstack()
...
>>> def lumberstack():
...     traceback.print_stack()
...     print(repr(traceback.extract_stack()))
...     print(repr(traceback.format_stack()))
...
>>> another_function()
  File "<doctest>", line 10, in <module>
    another_function()
  File "<doctest>", line 3, in another_function
    lumberstack()
  File "<doctest>", line 6, in lumberstack
    traceback.print_stack()
[('<doctest>', 10, '<module>', 'another_function()'),
 ('<doctest>', 3, 'another_function', 'lumberstack()'),
 ('<doctest>', 7, 'lumberstack', 'print(repr(traceback.extract_stack()))')]
['  File "<doctest>", line 10, in <module>\n    another_function()\n',
 '  File "<doctest>", line 3, in another_function\n    lumberstack()\n',
 '  File "<doctest>", line 8, in lumberstack\n    print(repr(traceback.format_stack()))\n']

这个最后一个示例演示了最后几个格式化函数

>>> import traceback
>>> traceback.format_list([('spam.py', 3, '<module>', 'spam.eggs()'),
...                        ('eggs.py', 42, 'eggs', 'return "bacon"')])
['  File "spam.py", line 3, in <module>\n    spam.eggs()\n',
 '  File "eggs.py", line 42, in eggs\n    return "bacon"\n']
>>> an_error = IndexError('tuple index out of range')
>>> traceback.format_exception_only(an_error)
['IndexError: tuple index out of range\n']

使用 TracebackException 的示例

借助辅助类,我们有更多的选择

>>> import sys
>>> from traceback import TracebackException
>>>
>>> def lumberjack():
...     bright_side_of_life()
...
>>> def bright_side_of_life():
...     t = "bright", "side", "of", "life"
...     return t[5]
...
>>> try:
...     lumberjack()
... except IndexError as e:
...     exc = e
...
>>> try:
...     try:
...         lumberjack()
...     except:
...         1/0
... except Exception as e:
...     chained_exc = e
...
>>> # limit works as with the module-level functions
>>> TracebackException.from_exception(exc, limit=-2).print()
Traceback (most recent call last):
  File "<python-input-1>", line 6, in lumberjack
    bright_side_of_life()
    ~~~~~~~~~~~~~~~~~~~^^
  File "<python-input-1>", line 10, in bright_side_of_life
    return t[5]
           ~^^^
IndexError: tuple index out of range

>>> # capture_locals adds local variables in frames
>>> TracebackException.from_exception(exc, limit=-2, capture_locals=True).print()
Traceback (most recent call last):
  File "<python-input-1>", line 6, in lumberjack
    bright_side_of_life()
    ~~~~~~~~~~~~~~~~~~~^^
  File "<python-input-1>", line 10, in bright_side_of_life
    return t[5]
           ~^^^
    t = ("bright", "side", "of", "life")
IndexError: tuple index out of range

>>> # The *chain* kwarg to print() controls whether chained
>>> # exceptions are displayed
>>> TracebackException.from_exception(chained_exc).print()
Traceback (most recent call last):
  File "<python-input-19>", line 4, in <module>
    lumberjack()
    ~~~~~~~~~~^^
  File "<python-input-8>", line 7, in lumberjack
    bright_side_of_life()
    ~~~~~~~~~~~~~~~~~~~^^
  File "<python-input-8>", line 11, in bright_side_of_life
    return t[5]
           ~^^^
IndexError: tuple index out of range

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<python-input-19>", line 6, in <module>
    1/0
    ~^~
ZeroDivisionError: division by zero

>>> TracebackException.from_exception(chained_exc).print(chain=False)
Traceback (most recent call last):
  File "<python-input-19>", line 6, in <module>
    1/0
    ~^~
ZeroDivisionError: division by zero