"traceback" —— 打印或读取栈回溯信息
***********************************

**源代码：** Lib/traceback.py

======================================================================

该模块提供了一个标准接口来提取、格式化和打印 Python 程序的栈跟踪结果。
它完全模仿Python 解释器在打印栈跟踪结果时的行为。当您想要在程序控制下
打印栈跟踪结果时，例如在“封装”解释器时，这是非常有用的。

这个模块使用 traceback 对象 —— 这是存储在 "sys.last_traceback" 中的对
象类型变量，并作为 "sys.exc_info()" 的第三项被返回。

这个模块定义了以下函数：

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

   如果*limit*是正整数，那么从 traceback 对象 "tb" 输出最高 *limit* 个
   （从调用函数开始的）栈的堆栈回溯‎条目‎；如果 *limit* 是负数就输出
   "abs(limit)" 个回溯条目；又如果 *limit* 被省略或者为 "None" ，那么
   就会输出所有回溯条目。如果 *file* 被省略或为 "None" 那么就会输出至
   标准输出 "sys.stderr" 否则它应该是一个打开的文件或者文件类对象来接
   收输出

   在 3.5 版更改: 添加了对负数值 *limit* 的支持

traceback.print_exception(etype, value, tb, limit=None, file=None, chain=True)

   打印回溯对象 *tb* 到 *file* 的异常信息和整个堆栈回溯。这和
   "print_tb()" 比有以下方面不同：

   * 如果 *tb* 不为 "None"，它将打印头部 "Traceback (most recent call
     last):"

   * 它将在输出完堆栈回溯后，输出异常中的  *etype* 和 *value* 信息

   * 如果 *type(value)* 为 "SyntaxError" 且 *value* 具有适当的格式，它
     会打印发生语法错误的行并用一个圆点来指明错误的大致位置。

   可选的 *limit* 参数具有与 "print_tb()" 的相同含义。 如果 *chain* 为
   真值（默认），则链式异常（异常的 "__cause__" 或 "__context__" 属性
   ）也将被打印出来，就像解释器本身在打印未处理的异常时一样。

   在 3.5 版更改: *etype* 参数会被忽略并根据 *value* 推断出来。

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

   这是 "print_exception(*sys.exc_info(), limit, file, chain)" 的简写
   。

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

   这是 "print_exception(sys.last_type, sys.last_value,
   sys.last_traceback, limit, file, chain)" 的简写。 通常它将只在异常
   到达交互提示之后才会起作用 (参见 "sys.last_type")。

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" 对象，其中包含代表通常为栈回溯打印的信息的
   "filename", "lineno", "name" 和 "line" 等属性。 "line" 是一个去除了
   前导和末尾空白符的字符串；如果源代码不可用则它将为 "None"。

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

   从当前的栈帧提取原始回溯信息。 返回值具有与 "extract_tb()" 的相同格
   式。 可选的 *f* 和 *limit* 参数具有与 "print_stack()" 的相同含义。

traceback.format_list(extracted_list)

   给定一个由元组或如 "extract_tb()" 或 "extract_stack()" 所返回的
   "FrameSummary" 对象组成的列表，返回一个可打印的字符串列表。 结果列
   表中的每个字符串都对应于参数列表中具有相同索引号的条目。 每个字符串
   以一个换行符结束；对于那些源文本行不为 "None" 的条目，字符串也可能
   包含内部换行符。

traceback.format_exception_only(etype, value)

   Format the exception part of a traceback.  The arguments are the
   exception type and value such as given by "sys.last_type" and
   "sys.last_value". The return value is a list of strings, each
   ending in a newline.  Normally, the list contains a single string;
   however, for "SyntaxError" exceptions, it contains several lines
   that (when printed) display detailed information about where the
   syntax error occurred.  The message indicating which exception
   occurred is the always last string in the list.

traceback.format_exception(etype, value, tb, limit=None, chain=True)

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

   在 3.5 版更改: *etype* 参数会被忽略并根据 *value* 推断出来。

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" 之后的栈，产生每一帧的帧和行号。 如果
   *f* 为 "None"，则会使用当前栈。 这个辅助函数要与
   "StackSummary.extract()" 一起使用。

   3.5 新版功能.

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)

   捕获一个异常以便随后渲染。 *limit*, *lookup_lines* 和
   *capture_locals* 的含义与 "StackSummary" 类的相同。

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

   __cause__

      原始 "__cause__" 的 "TracebackException"。

   __context__

      原始 "__context__" 的 "TracebackException"。

   __suppress_context__

      来自原始异常的 "__suppress_context__"。

   stack

      代表回溯的 "StackSummary"。

   exc_type

      原始回溯的类。

   filename

      针对语法错误 —— 错误发生所在的文件名。

   lineno

      针对语法错误 —— 错误发生所在的行号。

   text

      针对语法错误 —— 错误发生所在的文本。

   offset

      针对语法错误 —— 错误发生所在的文本内部的偏移量。

   msg

      针对语法错误 —— 编译器错误消息。

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

      捕获一个异常以便随后渲染。 *limit*, *lookup_lines* 和
      *capture_locals* 的含义与 "StackSummary" 类的相同。

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

   format(*, chain=True)

      格式化异常。

      如果 *chain* 不为 "True"，则 "__cause__" 和 "__context__" 将不会
      被格式化。

      返回值是一个字符串的生成器，其中每个字符串都以换行符结束并且有些
      还会包含内部换行符。 "print_exception()" 是此方法的一个包装器，
      它只是将这些行打印到一个文件。

      指明发生了哪种异常的消息总会是输出中的最后一个字符串。

   format_exception_only()

      格式化回溯的异常部分。

      返回值是一个字符串的生成器，每个字符串都以一个换行符结束。

      通常，生成器会发出单个字符串；不过，对于 "SyntaxError" 异常，它
      会发出（当打印时）显示有关语法错误发生在何处的详细信息的多个行。

      指明发生了哪种异常的消息总会是输出中的最后一个字符串。


"StackSummary" 对象
===================

3.5 新版功能.

代表一个可被格式化的调用栈的 "StackSummary" 对象。

class traceback.StackSummary

   classmethod extract(frame_gen, *, limit=None, lookup_lines=True, capture_locals=False)

      构造一个来自帧生成器的 "StackSummary" 对象（如 "walk_stack()" 或
      "walk_tb()" 所返回的一样）。

      如果提供了 *limit*，则只从 *frame_gen* 提取指定数量的帧。 如果
      *lookup_lines* 为 "False"，则返回的 "FrameSummary" 对象将不会读
      入它们的行，这使得创建 "StackSummary" 的开销更低（如果它不会被实
      际格式化这就会很有价值）。 如果 *capture_locals* 为 "True" 则每
      个 "FrameSummary" 中的局部变量会被捕获为对象表示形式。

   classmethod from_list(a_list)

      从所提供的 "FrameSummary" 对象列表或旧式的元组列表构造一个
      "StackSummary" 对象。 每个元组都应当是以文件、行号、名称和行为元
      素的 4 元组。

   format()

      返回一个可打印的字符串列表。 结果列表中的每个字符串各自对应来自
      于栈的单独帧。 每个字符串都以一个换行符结束；对于带有源文本行的
      条目来说，字符串还可能包含内部换行符。

      对于同一帧与行的长序列，将显示前几个重复项，后面跟一个指明之后的
      实际重复次数的摘要行。

      在 3.6 版更改: 重复帧的长序列现在将被缩减。


"FrameSummary" 对象
===================

3.5 新版功能.

"FrameSummary" 对象代表回溯中的一个单独帧。

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

   代表回溯或栈中被格式化或打印的一个单独帧。 它有时可能还带有包括在其
   中的帧局部变量的字符串化版本。 如果 *lookup_line* 为 "False"，则不
   会查找源代码直到 "FrameSummary" 已经访问了 "line" 属性（这还将发生
   在将其转换为元组时）。 "line" 可能会被直接提供，并将完全阻止行查找
   的发生。 *locals* 是一个可选的局部变量字典，如果有提供的话这些变量
   的表示形式将被存储在摘要中以便随后显示。


回溯示例
========

这个简单示例是一个基本的读取-求值-打印循环，类似于（但实用性小于）标准
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_death()

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

   try:
       lumberjack()
   except IndexError:
       exc_type, exc_value, exc_traceback = sys.exc_info()
       print("*** print_tb:")
       traceback.print_tb(exc_traceback, limit=1, file=sys.stdout)
       print("*** print_exception:")
       # exc_type below is ignored on 3.5 and later
       traceback.print_exception(exc_type, exc_value, exc_traceback,
                                 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:")
       # exc_type below is ignored on 3.5 and later
       print(repr(traceback.format_exception(exc_type, exc_value,
                                             exc_traceback)))
       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_death()
   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_death()
   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...>", line 10, in <module>\n    lumberjack()\n',
    '  File "<doctest...>", line 4, in lumberjack\n    bright_side_of_death()\n',
    '  File "<doctest...>", line 7, in bright_side_of_death\n    return tuple()[0]\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_death>]
   *** format_tb:
   ['  File "<doctest...>", line 10, in <module>\n    lumberjack()\n',
    '  File "<doctest...>", line 4, in lumberjack\n    bright_side_of_death()\n',
    '  File "<doctest...>", line 7, in bright_side_of_death\n    return tuple()[0]\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(type(an_error), an_error)
   ['IndexError: tuple index out of range\n']
