跳转至

6.11.traceback

Windows 10
Python 3.7.3 @ MSC v.1915 64 bit (AMD64)
Latest build date 2020.08.11
from toolkit import H
import re
import numpy as np
import traceback
import sys

FrameSummary 类

FrameSummary对象:表示trace back中的单个frame。它可以选择包含一个框架局部变量的字符串化版本。

traceback.FrameSummary(filename, lineno, name, lookup_line=True,
                       locals=None, line=None)
  • 如果 lookup_line 是 False ,直到 FrameSummary 有 line 访问的属性(在将其强制转换为元组时也会发生这种情况)。

  • line 可以直接提供,并且可以完全阻止行查找的发生。

  • locals 是可选的局部变量字典,如果提供,变量表示形式将存储在摘要中以供以后显示。

# 获取当前frame
frame = sys._getframe()
# 利用当前frame的信息创建一个FrameSummary对象
traceback.FrameSummary(filename=frame.f_code.co_filename,
                       lineno=frame.f_lineno,
                       name=frame.f_code.co_name,
                       lookup_line=True,
                       locals=frame.f_locals,
                       line=None)
<FrameSummary file <ipython-input-1-8a9a38cc1974>, line 2 in <module>>

StackSummary 类

StackSummary对象:表示准备格式化的调用堆栈。StackSummary对象是包含多个FrameSummary对象的可迭代容器。

构造方法

traceback.StackSummary.extract(frame_gen, limit=None,
                               lookup_lines=True,
                               capture_locals=False)
  • frame生成器:e.g. walk_stack()walk_tb()

  • limit:只从 frame_gen 提取 limit 个 frame 对象

  • lookup_lines:如果是False ,则返回的FrameSummary对象尚未读取其行,因此创建 StackSummary 的代价比较低(如果不是真正格式化的话可能很有价值)。

  • capture_locals:如果是True 则每个FrameSummary的局部变量会被捕获,用一个对象表示。

traceback.StackSummary.from_list(a_list)

从提供的旧样式的元组列表构造一个StackSummary对象。每个元组应该是filename,lineno,name,line为元素的4元组。

其他方法

traceback.StackSummary.format(self)

返回准备打印的字符串列表。

列表中的每一个元素(字符串)对应于堆栈中的一个frame。每个字符串以换行符结尾,对于具有源文本行的项目,字符串也可以包含内部换行符。对于同一帧和同一行的长序列,显示前几次重复,然后显示摘要行,说明进一步重复的确切数量。

获取 frame 堆栈

traceback.walk_stack(f)

从给frame中跟踪f.f_back后的堆栈,得到每个帧的帧和行号。如果f为None,则使用当前堆栈。它与StackSummary.extract()一起使用。

traceback.walk_tb(tb)

tb_next之后执行回溯,得到每个帧的帧和行号。它与StackSummary.extract()一起使用。

示例

def call_function(f, recursion_level=2):
    if recursion_level:
        return call_function(f, recursion_level - 1)
    else:
        return f()

def f():
    summary = traceback.StackSummary.extract(
        traceback.walk_stack(None)
    )
    return ''.join(summary.format())

def format_traceback_str(string):
    need_replaced = re.findall(r'"(.*)"', string)
    need_replaced_unique = []
    for i in need_replaced:
        if i not in need_replaced_unique:
            need_replaced_unique.append(i)

    num = 1
    for file_str in need_replaced_unique:
        if num > 3:
            output_end_index = string.index(f'"{num - 1}.py"')
            string = string[0:output_end_index]
            break
        if not file_str.startswith("<ipython-input"):
            string = string.replace(file_str, f"{num}.py")
            num += 1

    return string


print('Calling f() directly:')
string = f()
print(format_traceback_str(string))

print()
print('Calling f() from 3 levels deep:')
string = call_function(f)
print(format_traceback_str(string))
Calling f() directly:
  File "<ipython-input-1-8548a9dafead>", line 9, in f
    traceback.walk_stack(None)
  File "<ipython-input-1-8548a9dafead>", line 34, in <module>
    string = f()
  File "1.py", line 3331, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "1.py", line 3254, in run_ast_nodes
    if (await self.run_code(code, result,  async_=asy)):
  File "1.py", line 3063, in run_cell_async
    interactivity=interactivity, compiler=compiler, result=result)
  File "2.py", line 68, in _pseudo_sync_runner
    coro.send(None)
  File "1.py", line 2886, in _run_cell
    return runner(coro)
  File "1.py", line 2858, in run_cell
    raw_cell, store_history, silent, shell_futures)
  File

Calling f() from 3 levels deep:
  File "<ipython-input-1-8548a9dafead>", line 9, in f
    traceback.walk_stack(None)
  File "<ipython-input-1-8548a9dafead>", line 5, in call_function
    return f()
  File "<ipython-input-1-8548a9dafead>", line 3, in call_function
    return call_function(f, recursion_level - 1)
  File "<ipython-input-1-8548a9dafead>", line 3, in call_function
    return call_function(f, recursion_level - 1)
  File "<ipython-input-1-8548a9dafead>", line 39, in <module>
    string = call_function(f)
  File "1.py", line 3331, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "1.py", line 3254, in run_ast_nodes
    if (await self.run_code(code, result,  async_=asy)):
  File "1.py", line 3063, in run_cell_async
    interactivity=interactivity, compiler=compiler, result=result)
  File "2.py", line 68, in _pseudo_sync_runner
    coro.send(None)
  File "1.py", line 2886, in _run_cell
    return runner(coro)
  File "1.py", line 2858, in run_cell
    raw_cell, store_history, silent, shell_futures)
  File

为了显示更简洁的结果,trackback信息中的Python文件名用数字代替,并且省略一些末尾的trackback信息,这个过程由format_traceback_str函数完成。省略的信息在f()call_function(f)返回的结果中都是相同的。

实际上,我们完全可以自定义trackback字符串的格式:

import traceback
import sys

template = (
    '"{fs.filename:<26}":{fs.lineno}:{fs.name}:\n'
    '    {fs.line}'
)

def f():
    summary = traceback.StackSummary.extract(
        traceback.walk_stack(None)
    )
    string = ""
    for fs in summary:
        string += template.format(fs=fs) + "\n"
    return string


print('Calling f() directly:')
string = f()
print(format_traceback_str(string))

print()
print('Calling f() from 3 levels deep:')
string = call_function(f)
print(format_traceback_str(string))
Calling f() directly:
"<ipython-input-1-4b8f40d1d7c9>":11:f:
    traceback.walk_stack(None)
"<ipython-input-1-4b8f40d1d7c9>":20:<module>:
    string = f()
"1.py":3331:run_code:
    exec(code_obj, self.user_global_ns, self.user_ns)
"1.py":3254:run_ast_nodes:
    if (await self.run_code(code, result,  async_=asy)):
"1.py":3063:run_cell_async:
    interactivity=interactivity, compiler=compiler, result=result)
"2.py":68:_pseudo_sync_runner:
    coro.send(None)
"1.py":2886:_run_cell:
    return runner(coro)
"1.py":2858:run_cell:
    raw_cell, store_history, silent, shell_futures)


Calling f() from 3 levels deep:
"<ipython-input-1-4b8f40d1d7c9>":11:f:
    traceback.walk_stack(None)
"<ipython-input-1-8548a9dafead>":5:call_function:
    return f()
"<ipython-input-1-8548a9dafead>":3:call_function:
    return call_function(f, recursion_level - 1)
"<ipython-input-1-8548a9dafead>":3:call_function:
    return call_function(f, recursion_level - 1)
"<ipython-input-1-4b8f40d1d7c9>":25:<module>:
    string = call_function(f)
"1.py":3331:run_code:
    exec(code_obj, self.user_global_ns, self.user_ns)
"1.py":3254:run_ast_nodes:
    if (await self.run_code(code, result,  async_=asy)):
"1.py":3063:run_cell_async:
    interactivity=interactivity, compiler=compiler, result=result)
"2.py":68:_pseudo_sync_runner:
    coro.send(None)
"1.py":2886:_run_cell:
    return runner(coro)
"1.py":2858:run_cell:
    raw_cell, store_history, silent, shell_futures)

TracebackException

import traceback
import sys

def produce_exception(recursion_level=2):
    sys.stdout.flush()
    if recursion_level:
        produce_exception(recursion_level - 1)
    else:
        raise RuntimeError()

print('with no exception:')
exc_type, exc_value, exc_tb = sys.exc_info()
tbe = traceback.TracebackException(exc_type, exc_value, exc_tb)
print(''.join(tbe.format()))

print('\nwith exception:')
try:
    produce_exception()
except Exception as err:
    exc_type, exc_value, exc_tb = sys.exc_info()

    tbe = traceback.TracebackException(
        exc_type, exc_value, exc_tb,
    )

    print(''.join(tbe.format()))

    print('\nexception only:')
    print(''.join(tbe.format_exception_only()))
with no exception:
None: None


with exception:
Traceback (most recent call last):
  File "<ipython-input-1-9d9c5e9aab70>", line 18, in <module>
    produce_exception()
  File "<ipython-input-1-9d9c5e9aab70>", line 7, in produce_exception
    produce_exception(recursion_level - 1)
  File "<ipython-input-1-9d9c5e9aab70>", line 7, in produce_exception
    produce_exception(recursion_level - 1)
  File "<ipython-input-1-9d9c5e9aab70>", line 9, in produce_exception
    raise RuntimeError()
RuntimeError


exception only:
RuntimeError

底层异常 API

另一个处理异常报告的方法是使用print_exc()。它使用sys.exc_info()来为当前线程存储异常信息,格式化结果,打印文本到文件句柄(默认是 sys.stderr)。

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

print_exc()不需要传入参数,所以在一些场合print_exc()可能无法获得预期的结果。例如在Python 2.x中执行下述代码:

import traceback

try:
    raise TypeError("Oups!")
except Exception:
    try:
        raise TypeError("Again !?!")
    except:
        pass

    traceback.print_exc()
Traceback (most recent call last):
  File "<ipython-input-1-057ba94a4e04>", line 4, in <module>
    raise TypeError("Oups!")
TypeError: Oups!

我们可能期待print_exc()打印出raise TypeError("Again !?!")语句抛出的异常,但实际上,print_exc()只打印了raise TypeError("Oups!")语句抛出的异常。

print_exc()只是print_exception()的快捷方式,只不过我们使用后者时需要准确的参数print_exception()的参数通过sys.exc_info()获取到。

如果您确实需要访问原始的追溯,一种解决方案是将异常信息从exc_info本地变量中返回,并使用来显示它print_exception

import traceback
import sys


try:
    raise TypeError("Oups!")
except Exception:
    try:
        exc_info = sys.exc_info()
        print(exc_info)

        # do you usefull stuff here
        # (potentially raising an exception)
        try:
            raise TypeError("Again !?!")
        except:
            pass
        # end of useful stuff

    finally:
        # Display the *original* exception
        traceback.print_exception(*exc_info)
        del exc_info


# https://stackoverflow.com/questions/3702675/how-to-print-the-full-traceback-without-halting-the-program

# a = []
# for i in traceback.walk_stack(None):
#     a.append(i)

# dir(a[0][0])
# frame.f_back

# a[0][0].f_code
(<class 'TypeError'>, TypeError('Oups!'), <traceback object at
0x000001309FD2E308>)
Traceback (most recent call last):
  File "<ipython-input-1-c2358bda325a>", line 6, in <module>
    raise TypeError("Oups!")
TypeError: Oups!

print_exception()使用的是format_exception()来准备要打印的文本。format_exception()要使用的三个参数与print_exception()一样,都是exception type, exception value, traceback。

import traceback
import sys
from pprint import pprint

try:
    produce_exception()
except Exception as err:
    print('format_exception():')
    exc_type, exc_value, exc_tb = sys.exc_info()
    pprint(
        traceback.format_exception(exc_type, exc_value, exc_tb),
        width=65,
    )
format_exception():
['Traceback (most recent call last):\n',
 '  File "<ipython-input-1-564aebc46497>", line 6, in <module>\n'
 '    produce_exception()\n',
 '  File "<ipython-input-1-9d9c5e9aab70>", line 7, in '
 'produce_exception\n'
 '    produce_exception(recursion_level - 1)\n',
 '  File "<ipython-input-1-9d9c5e9aab70>", line 7, in '
 'produce_exception\n'
 '    produce_exception(recursion_level - 1)\n',
 '  File "<ipython-input-1-9d9c5e9aab70>", line 9, in '
 'produce_exception\n'
 '    raise RuntimeError()\n',
 'RuntimeError\n']

要想把 traceback 用其他方式处理,比如弄成不同的输出格式,我们可以用 extract_tb() 获取出数据。

import traceback
import sys
import os

template = '{filename:<23}:{linenum}:{funcname}:\n    {source}'

try:
    produce_exception()
except Exception as err:
    print('format_exception():')
    exc_type, exc_value, exc_tb = sys.exc_info()
    for tb_info in traceback.extract_tb(exc_tb):
        filename, linenum, funcname, source = tb_info
        if funcname != '<module>':
            funcname = funcname + '()'
        print(template.format(
            filename=os.path.basename(filename),
            linenum=linenum,
            source=source,
            funcname=funcname)
        )
format_exception():
<ipython-input-1-5f837b49071f>:8:<module>:
    produce_exception()
<ipython-input-1-9d9c5e9aab70>:7:produce_exception():
    produce_exception(recursion_level - 1)
<ipython-input-1-9d9c5e9aab70>:7:produce_exception():
    produce_exception(recursion_level - 1)
<ipython-input-1-9d9c5e9aab70>:9:produce_exception():
    raise RuntimeError()

底层栈 API

有几个与 traceback 相同的函数来对当前调用栈做相同的操作。print_stack() 会打印出当前栈但不引发异常。输出很像 traceback 但并无错误信息。

import traceback
import sys

def f():
    traceback.print_stack(file=sys.stdout)

print('Calling f() directly:')
f()

print()
print('Calling f() from 3 levels deep:')
call_function(f)
Calling f() directly:
  File "setup_m.py", line 45, in <module>
    save_dir=save_dir)
  File "G:\Installed\Anaconda3\lib\site-packages\pweave\__init__.py",
line 62, in weave
    doc.weave()
  File "G:\Installed\Anaconda3\lib\site-packages\pweave\pweb.py", line
192, in weave
    self.run()
  File "G:\Installed\Anaconda3\lib\site-packages\pweave\pweb.py", line
129, in run
    proc.run()
  File "G:\Installed\Anaconda3\lib\site-
packages\pweave\processors\base.py", line 46, in run
    res = self._runcode(chunk)
  File "G:\Installed\Anaconda3\lib\site-
packages\pweave\processors\base.py", line 171, in _runcode
    chunk['result'] = self.loadstring(chunk['content'], chunk=chunk)
  File "G:\Installed\Anaconda3\lib\site-
packages\pweave\processors\jupyter.py", line 134, in loadstring
    return self.run_cell(code_str)
  File "G:\Installed\Anaconda3\lib\site-
packages\pweave\processors\jupyter.py", line 58, in run_cell
    msg_id = self.kc.execute(src.lstrip(), store_history=False)
  File "G:\Installed\Anaconda3\lib\site-
packages\ipykernel\inprocess\client.py", line 102, in execute
    self._dispatch_to_kernel(msg)
  File "G:\Installed\Anaconda3\lib\site-
packages\ipykernel\inprocess\client.py", line 170, in
_dispatch_to_kernel
    kernel.dispatch_shell(stream, msg_parts)
  File "G:\Installed\Anaconda3\lib\site-packages\tornado\gen.py", line
209, in wrapper
    yielded = next(result)
  File "G:\Installed\Anaconda3\lib\site-
packages\ipykernel\kernelbase.py", line 268, in dispatch_shell
    yield gen.maybe_future(handler(stream, idents, msg))
  File "G:\Installed\Anaconda3\lib\site-
packages\ipykernel\inprocess\ipkernel.py", line 80, in execute_request
    super(InProcessKernel, self).execute_request(stream, ident,
parent)
  File "G:\Installed\Anaconda3\lib\site-packages\tornado\gen.py", line
209, in wrapper
    yielded = next(result)
  File "G:\Installed\Anaconda3\lib\site-
packages\ipykernel\kernelbase.py", line 541, in execute_request
    user_expressions, allow_stdin,
  File "G:\Installed\Anaconda3\lib\site-packages\tornado\gen.py", line
209, in wrapper
    yielded = next(result)
  File "G:\Installed\Anaconda3\lib\site-
packages\ipykernel\ipkernel.py", line 300, in do_execute
    res = shell.run_cell(code, store_history=store_history,
silent=silent)
  File "G:\Installed\Anaconda3\lib\site-
packages\ipykernel\zmqshell.py", line 536, in run_cell
    return super(ZMQInteractiveShell, self).run_cell(*args, **kwargs)
  File "G:\Installed\Anaconda3\lib\site-
packages\IPython\core\interactiveshell.py", line 2858, in run_cell
    raw_cell, store_history, silent, shell_futures)
  File "G:\Installed\Anaconda3\lib\site-
packages\IPython\core\interactiveshell.py", line 2886, in _run_cell
    return runner(coro)
  File "G:\Installed\Anaconda3\lib\site-
packages\IPython\core\async_helpers.py", line 68, in
_pseudo_sync_runner
    coro.send(None)
  File "G:\Installed\Anaconda3\lib\site-
packages\IPython\core\interactiveshell.py", line 3063, in
run_cell_async
    interactivity=interactivity, compiler=compiler, result=result)
  File "G:\Installed\Anaconda3\lib\site-
packages\IPython\core\interactiveshell.py", line 3254, in
run_ast_nodes
    if (await self.run_code(code, result,  async_=asy)):
  File "G:\Installed\Anaconda3\lib\site-
packages\IPython\core\interactiveshell.py", line 3331, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-1-fb615fd1c94c>", line 8, in <module>
    f()
  File "<ipython-input-1-fb615fd1c94c>", line 5, in f
    traceback.print_stack(file=sys.stdout)

Calling f() from 3 levels deep:
  File "setup_m.py", line 45, in <module>
    save_dir=save_dir)
  File "G:\Installed\Anaconda3\lib\site-packages\pweave\__init__.py",
line 62, in weave
    doc.weave()
  File "G:\Installed\Anaconda3\lib\site-packages\pweave\pweb.py", line
192, in weave
    self.run()
  File "G:\Installed\Anaconda3\lib\site-packages\pweave\pweb.py", line
129, in run
    proc.run()
  File "G:\Installed\Anaconda3\lib\site-
packages\pweave\processors\base.py", line 46, in run
    res = self._runcode(chunk)
  File "G:\Installed\Anaconda3\lib\site-
packages\pweave\processors\base.py", line 171, in _runcode
    chunk['result'] = self.loadstring(chunk['content'], chunk=chunk)
  File "G:\Installed\Anaconda3\lib\site-
packages\pweave\processors\jupyter.py", line 134, in loadstring
    return self.run_cell(code_str)
  File "G:\Installed\Anaconda3\lib\site-
packages\pweave\processors\jupyter.py", line 58, in run_cell
    msg_id = self.kc.execute(src.lstrip(), store_history=False)
  File "G:\Installed\Anaconda3\lib\site-
packages\ipykernel\inprocess\client.py", line 102, in execute
    self._dispatch_to_kernel(msg)
  File "G:\Installed\Anaconda3\lib\site-
packages\ipykernel\inprocess\client.py", line 170, in
_dispatch_to_kernel
    kernel.dispatch_shell(stream, msg_parts)
  File "G:\Installed\Anaconda3\lib\site-packages\tornado\gen.py", line
209, in wrapper
    yielded = next(result)
  File "G:\Installed\Anaconda3\lib\site-
packages\ipykernel\kernelbase.py", line 268, in dispatch_shell
    yield gen.maybe_future(handler(stream, idents, msg))
  File "G:\Installed\Anaconda3\lib\site-
packages\ipykernel\inprocess\ipkernel.py", line 80, in execute_request
    super(InProcessKernel, self).execute_request(stream, ident,
parent)
  File "G:\Installed\Anaconda3\lib\site-packages\tornado\gen.py", line
209, in wrapper
    yielded = next(result)
  File "G:\Installed\Anaconda3\lib\site-
packages\ipykernel\kernelbase.py", line 541, in execute_request
    user_expressions, allow_stdin,
  File "G:\Installed\Anaconda3\lib\site-packages\tornado\gen.py", line
209, in wrapper
    yielded = next(result)
  File "G:\Installed\Anaconda3\lib\site-
packages\ipykernel\ipkernel.py", line 300, in do_execute
    res = shell.run_cell(code, store_history=store_history,
silent=silent)
  File "G:\Installed\Anaconda3\lib\site-
packages\ipykernel\zmqshell.py", line 536, in run_cell
    return super(ZMQInteractiveShell, self).run_cell(*args, **kwargs)
  File "G:\Installed\Anaconda3\lib\site-
packages\IPython\core\interactiveshell.py", line 2858, in run_cell
    raw_cell, store_history, silent, shell_futures)
  File "G:\Installed\Anaconda3\lib\site-
packages\IPython\core\interactiveshell.py", line 2886, in _run_cell
    return runner(coro)
  File "G:\Installed\Anaconda3\lib\site-
packages\IPython\core\async_helpers.py", line 68, in
_pseudo_sync_runner
    coro.send(None)
  File "G:\Installed\Anaconda3\lib\site-
packages\IPython\core\interactiveshell.py", line 3063, in
run_cell_async
    interactivity=interactivity, compiler=compiler, result=result)
  File "G:\Installed\Anaconda3\lib\site-
packages\IPython\core\interactiveshell.py", line 3254, in
run_ast_nodes
    if (await self.run_code(code, result,  async_=asy)):
  File "G:\Installed\Anaconda3\lib\site-
packages\IPython\core\interactiveshell.py", line 3331, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-1-fb615fd1c94c>", line 12, in <module>
    call_function(f)
  File "<ipython-input-1-8548a9dafead>", line 3, in call_function
    return call_function(f, recursion_level - 1)
  File "<ipython-input-1-8548a9dafead>", line 3, in call_function
    return call_function(f, recursion_level - 1)
  File "<ipython-input-1-8548a9dafead>", line 5, in call_function
    return f()
  File "<ipython-input-1-fb615fd1c94c>", line 5, in f
    traceback.print_stack(file=sys.stdout)

format_stack() 准备栈追踪的方式与 format_exception() 一样。

import traceback
import sys
from pprint import pprint


def f():
    return traceback.format_stack()

formatted_stack = call_function(f)
pprint(formatted_stack)
['  File "setup_m.py", line 45, in <module>\n
save_dir=save_dir)\n',
 '  File "G:\\Installed\\Anaconda3\\lib\\site-
packages\\pweave\\__init__.py", '
 'line 62, in weave\n'
 '    doc.weave()\n',
 '  File "G:\\Installed\\Anaconda3\\lib\\site-
packages\\pweave\\pweb.py", line '
 '192, in weave\n'
 '    self.run()\n',
 '  File "G:\\Installed\\Anaconda3\\lib\\site-
packages\\pweave\\pweb.py", line '
 '129, in run\n'
 '    proc.run()\n',
 '  File '
 '"G:\\Installed\\Anaconda3\\lib\\site-
packages\\pweave\\processors\\base.py", '
 'line 46, in run\n'
 '    res = self._runcode(chunk)\n',
 '  File '
 '"G:\\Installed\\Anaconda3\\lib\\site-
packages\\pweave\\processors\\base.py", '
 'line 171, in _runcode\n'
 "    chunk['result'] = self.loadstring(chunk['content'],
chunk=chunk)\n",
 '  File '
 '"G:\\Installed\\Anaconda3\\lib\\site-
packages\\pweave\\processors\\jupyter.py", '
 'line 134, in loadstring\n'
 '    return self.run_cell(code_str)\n',
 '  File '
 '"G:\\Installed\\Anaconda3\\lib\\site-
packages\\pweave\\processors\\jupyter.py", '
 'line 58, in run_cell\n'
 '    msg_id = self.kc.execute(src.lstrip(), store_history=False)\n',
 '  File '
 '"G:\\Installed\\Anaconda3\\lib\\site-
packages\\ipykernel\\inprocess\\client.py", '
 'line 102, in execute\n'
 '    self._dispatch_to_kernel(msg)\n',
 '  File '
 '"G:\\Installed\\Anaconda3\\lib\\site-
packages\\ipykernel\\inprocess\\client.py", '
 'line 170, in _dispatch_to_kernel\n'
 '    kernel.dispatch_shell(stream, msg_parts)\n',
 '  File "G:\\Installed\\Anaconda3\\lib\\site-
packages\\tornado\\gen.py", line '
 '209, in wrapper\n'
 '    yielded = next(result)\n',
 '  File '
 '"G:\\Installed\\Anaconda3\\lib\\site-
packages\\ipykernel\\kernelbase.py", '
 'line 268, in dispatch_shell\n'
 '    yield gen.maybe_future(handler(stream, idents, msg))\n',
 '  File '
 '"G:\\Installed\\Anaconda3\\lib\\site-
packages\\ipykernel\\inprocess\\ipkernel.py", '
 'line 80, in execute_request\n'
 '    super(InProcessKernel, self).execute_request(stream, ident,
parent)\n',
 '  File "G:\\Installed\\Anaconda3\\lib\\site-
packages\\tornado\\gen.py", line '
 '209, in wrapper\n'
 '    yielded = next(result)\n',
 '  File '
 '"G:\\Installed\\Anaconda3\\lib\\site-
packages\\ipykernel\\kernelbase.py", '
 'line 541, in execute_request\n'
 '    user_expressions, allow_stdin,\n',
 '  File "G:\\Installed\\Anaconda3\\lib\\site-
packages\\tornado\\gen.py", line '
 '209, in wrapper\n'
 '    yielded = next(result)\n',
 '  File '
 '"G:\\Installed\\Anaconda3\\lib\\site-
packages\\ipykernel\\ipkernel.py", line '
 '300, in do_execute\n'
 '    res = shell.run_cell(code, store_history=store_history,
silent=silent)\n',
 '  File '
 '"G:\\Installed\\Anaconda3\\lib\\site-
packages\\ipykernel\\zmqshell.py", line '
 '536, in run_cell\n'
 '    return super(ZMQInteractiveShell, self).run_cell(*args,
**kwargs)\n',
 '  File '
 '"G:\\Installed\\Anaconda3\\lib\\site-
packages\\IPython\\core\\interactiveshell.py", '
 'line 2858, in run_cell\n'
 '    raw_cell, store_history, silent, shell_futures)\n',
 '  File '
 '"G:\\Installed\\Anaconda3\\lib\\site-
packages\\IPython\\core\\interactiveshell.py", '
 'line 2886, in _run_cell\n'
 '    return runner(coro)\n',
 '  File '
 '"G:\\Installed\\Anaconda3\\lib\\site-
packages\\IPython\\core\\async_helpers.py", '
 'line 68, in _pseudo_sync_runner\n'
 '    coro.send(None)\n',
 '  File '
 '"G:\\Installed\\Anaconda3\\lib\\site-
packages\\IPython\\core\\interactiveshell.py", '
 'line 3063, in run_cell_async\n'
 '    interactivity=interactivity, compiler=compiler,
result=result)\n',
 '  File '
 '"G:\\Installed\\Anaconda3\\lib\\site-
packages\\IPython\\core\\interactiveshell.py", '
 'line 3254, in run_ast_nodes\n'
 '    if (await self.run_code(code, result,  async_=asy)):\n',
 '  File '
 '"G:\\Installed\\Anaconda3\\lib\\site-
packages\\IPython\\core\\interactiveshell.py", '
 'line 3331, in run_code\n'
 '    exec(code_obj, self.user_global_ns, self.user_ns)\n',
 '  File "<ipython-input-1-175e8d8ff5b6>", line 9, in <module>\n'
 '    formatted_stack = call_function(f)\n',
 '  File "<ipython-input-1-8548a9dafead>", line 3, in call_function\n'
 '    return call_function(f, recursion_level - 1)\n',
 '  File "<ipython-input-1-8548a9dafead>", line 3, in call_function\n'
 '    return call_function(f, recursion_level - 1)\n',
 '  File "<ipython-input-1-8548a9dafead>", line 5, in call_function\n'
 '    return f()\n',
 '  File "<ipython-input-1-175e8d8ff5b6>", line 7, in f\n'
 '    return traceback.format_stack()\n']

extract_stack() 函数与 extract_tb() 差不多。

import traceback
import sys
import os


template = '{filename:<26}:{linenum}:{funcname}:\n    {source}'

def f():
    return traceback.extract_stack()

stack = call_function(f)
for filename, linenum, funcname, source in stack:
    if funcname != '<module>':
        funcname = funcname + '()'
    print(template.format(
        filename=os.path.basename(filename),
        linenum=linenum,
        source=source,
        funcname=funcname)
    )
setup_m.py                :45:<module>:
    save_dir=save_dir)
__init__.py               :62:weave():
    doc.weave()
pweb.py                   :192:weave():
    self.run()
pweb.py                   :129:run():
    proc.run()
base.py                   :46:run():
    res = self._runcode(chunk)
base.py                   :171:_runcode():
    chunk['result'] = self.loadstring(chunk['content'], chunk=chunk)
jupyter.py                :134:loadstring():
    return self.run_cell(code_str)
jupyter.py                :58:run_cell():
    msg_id = self.kc.execute(src.lstrip(), store_history=False)
client.py                 :102:execute():
    self._dispatch_to_kernel(msg)
client.py                 :170:_dispatch_to_kernel():
    kernel.dispatch_shell(stream, msg_parts)
gen.py                    :209:wrapper():
    yielded = next(result)
kernelbase.py             :268:dispatch_shell():
    yield gen.maybe_future(handler(stream, idents, msg))
ipkernel.py               :80:execute_request():
    super(InProcessKernel, self).execute_request(stream, ident,
parent)
gen.py                    :209:wrapper():
    yielded = next(result)
kernelbase.py             :541:execute_request():
    user_expressions, allow_stdin,
gen.py                    :209:wrapper():
    yielded = next(result)
ipkernel.py               :300:do_execute():
    res = shell.run_cell(code, store_history=store_history,
silent=silent)
zmqshell.py               :536:run_cell():
    return super(ZMQInteractiveShell, self).run_cell(*args, **kwargs)
interactiveshell.py       :2858:run_cell():
    raw_cell, store_history, silent, shell_futures)
interactiveshell.py       :2886:_run_cell():
    return runner(coro)
async_helpers.py          :68:_pseudo_sync_runner():
    coro.send(None)
interactiveshell.py       :3063:run_cell_async():
    interactivity=interactivity, compiler=compiler, result=result)
interactiveshell.py       :3254:run_ast_nodes():
    if (await self.run_code(code, result,  async_=asy)):
interactiveshell.py       :3331:run_code():
    exec(code_obj, self.user_global_ns, self.user_ns)
<ipython-input-1-ff723ef2e674>:11:<module>:
    stack = call_function(f)
<ipython-input-1-8548a9dafead>:3:call_function():
    return call_function(f, recursion_level - 1)
<ipython-input-1-8548a9dafead>:3:call_function():
    return call_function(f, recursion_level - 1)
<ipython-input-1-8548a9dafead>:5:call_function():
    return f()
<ipython-input-1-ff723ef2e674>:9:f():
    return traceback.extract_stack()

它还可以接受参数,但我们在这里并未使用,该参数的作用是使其从堆栈帧中的其他位置(层级)开始或限制遍历深度。

# https://blog.csdn.net/weixin_43193719/article/details/95518650
# https://www.osgeo.cn/cpython/library/traceback.html
# https://www.jianshu.com/p/a8cb5375171a
# https://groups.google.com/forum/#!topic/python-cn/bJHTBI9vhwc
# https://docs.python.org/3/library/inspect.html
# https://stackoverflow.com/questions/3702675/how-to-print-the-full-traceback-without-halting-the-program