堆栈和框架有什么区别?

jmu*_*sch 47 python sys inspect traceback

在什么情况下我想用一个而不是另一个?

有什么区别:

>>> import inspect
>>> print(inspect.getouterframes(inspect.currentframe()))
[(<frame object at 0x8fc262c>, '<stdin>', 1, '<module>', None, None)]
Run Code Online (Sandbox Code Playgroud)

和:

>>> import traceback
>>> traceback.extract_stack()
[('<stdin>', 1, '<module>', None)]
Run Code Online (Sandbox Code Playgroud)

更新:

另一个:

>>> import sys
>>> print(sys._getframe().f_trace,sys._getframe().f_code)
(None, <code object <module> at 0x8682a88, file "<stdin>", line 1>)
Run Code Online (Sandbox Code Playgroud)

我不明白这里的细微差别:

  • 堆栈框架
  • 框架对象
  • 堆栈跟踪

更新2,问题问题后的一段时间,但非常相关

roi*_*ppi 52

好吧,因为这似乎更多的是关于堆栈帧/调用堆栈的一般情况,让我们来看看:

def f():
    try:
        g()
    except:
        # WE WILL DO THINGS HERE

def g():
    h()

def h():
    raise Exception('stuff')

#CALL
f()
Run Code Online (Sandbox Code Playgroud)

当我们进入时h(),调用堆栈上有4个帧.

[top level]
 [f()]
  [g()]
   [h()] #<-- we're here
Run Code Online (Sandbox Code Playgroud)

(如果我们试图sys.getrecursionlimit()在堆栈上放置多个帧,我们会得到一个RuntimeError,这是python的版本StackOverflow;-))

"外部"指的是调用堆栈中我们上面的所有内容(字面意思是:"向上"方向).所以为了,gf,那么顶部(模块)的水平.同样,"内"是指一切向下调用堆栈.如果我们捕获一个异常f(),那个traceback对象将引用所有被解开的内部堆栈帧以使我们到达那一点.

def f():
    try:
        g()
    except:
        import inspect
        import sys
        #the third(last) item in sys.exc_info() is the current traceback object
        return inspect.getinnerframes(sys.exc_info()[-1])
Run Code Online (Sandbox Code Playgroud)

这给出了:

[(<frame object at 0xaad758>, 'test.py', 3, 'f', ['        g()\n'], 0), 
(<frame object at 0x7f5edeb23648>, 'test.py', 10, 'g', ['    h()\n'], 0), 
(<frame object at 0x7f5edeabdc50>, 'test.py', 13, 'h', ["    raise Exception('stuff')\n"], 0)]
Run Code Online (Sandbox Code Playgroud)

正如所料,三个内框架f,g和h.现在,我们可以采取的最后一帧的对象(一个来自h()),并要求其外部框架:

[(<frame object at 0x7f6e996e6a48>, 'test.py', 13, 'h', ["    raise Exception('stuff')\n"], 0), 
(<frame object at 0x1bf58b8>, 'test.py', 10, 'g', ['    h()\n'], 0), 
(<frame object at 0x7f6e99620240>, 'test.py', 7, 'f', ['        return inspect.getinnerframes(sys.exc_info()[-1])\n'], 0), 
(<frame object at 0x7f6e99725438>, 'test.py', 23, '<module>', ['print(inspect.getouterframes(f()[-1][0]))\n'], 0)]
Run Code Online (Sandbox Code Playgroud)

所以,你去了,就是这样:我们只是在导航调用堆栈.为了比较,这是traceback.extract_stack(f()[-1][0])给出的:

[('test.py', 23, '<module>', 'print(traceback.extract_stack(f()[-1][0]))'), 
('test.py', 7, 'f', 'return inspect.getinnerframes(sys.exc_info()[-1])'), 
('test.py', 10, 'g', 'h()'), 
('test.py', 13, 'h', "raise Exception('stuff')")]
Run Code Online (Sandbox Code Playgroud)

注意这里的反转顺序与getouterframes减少的输出相比较.事实上,如果你眯着眼睛,这基本上看起来像一个普通的回溯(哎,这就是,只有一点点更多的格式).

总结:既inspect.getouterframestraceback.extract_stack包含的所有信息复制你在你的日常回溯一般见到的; extract_stack只是删除对堆栈帧的引用,因为一旦你从一个给定的帧向外格式化堆栈跟踪,它就不再需要它们了.


Bre*_*arn 10

该文档inspect模块,说:

当以下函数返回"帧记录"时,每个记录是六个项目的元组:框架对象,文件名,当前行的行号,函数名称,源代码中的上下文行列表,以及该列表中当前行的索引.

该文档traceback模块,说:

"预处理"堆栈跟踪条目是4元组(文件名,行号,函数名,文本)

因此,不同的是,帧记录还包括框对象和背景的一些线,而回溯只包括各行的在调用堆栈中的文本(即,导致调用extract_stack呼叫).

traceback如果您只想打印回溯,可以使用堆栈.如文档所示,这是为了向用户显示而处理的信息.inspect如果您想要实际对调用堆栈执行任何操作(例如,从调用帧读取变量),则需要访问框架对象.