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