在什么情况下我想用一个而不是另一个?
有什么区别:
>>> import inspect
>>> print(inspect.getouterframes(inspect.currentframe()))
[(<frame object at 0x8fc262c>, '<stdin>', 1, '<module>', None, None)]
和
>>> import traceback
>>> traceback.extract_stack()
[('<stdin>', 1, '<module>', None)]
更新
另:
>>> import sys
>>> print(sys._getframe().f_trace,sys._getframe().f_code)
(None, <code object <module> at 0x8682a88, file "<stdin>", line 1>)
我不明白这里的细微差别:
更新2,问题问题后的一段时间,但非常相关
答案 0 :(得分:53)
好吧,因为这似乎更多地是关于堆栈帧/调用堆栈的一般情况,让我们来看看:
def f():
try:
g()
except:
# WE WILL DO THINGS HERE
def g():
h()
def h():
raise Exception('stuff')
#CALL
f()
当我们进入h()
时,call stack上有4个框架。
[top level]
[f()]
[g()]
[h()] #<-- we're here
(如果我们尝试在堆栈上放置超过sys.getrecursionlimit()
个帧,我们将获得RuntimeError
,这是StackOverflow
的python版本; - ))< / p>
&#34;外&#34;指的是调用堆栈中我们上面的所有内容(字面意思:方向&#34; up&#34;)。那么按顺序,g
,然后是f
,然后是顶级(模块)级别。同样地,&#34;内部&#34;指的是调用堆栈中的所有向下。如果我们在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])
这给出了:
[(<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)]
正如预期的那样,三个内框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)]
所以,你去了,那就是所有的事情:我们只是简单地导航调用堆栈。为了比较,这是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')")]
注意此处的反转顺序与getouterframes
相比,减少了输出。事实上,如果你眯着眼睛,这基本上看起来像一个常规的追溯(嘿,它是,只需要更多的格式化)。
总结:inspect.getouterframes
和traceback.extract_stack
都包含所有信息,以重现您在日常追溯中通常看到的内容; extract_stack
只是删除了对堆栈帧的引用,因为一旦你从一个给定的帧向外格式化堆栈跟踪,它就不再需要它们了。
答案 1 :(得分:10)
inspect
模块的
当以下函数返回“帧记录”时,每个记录是六个项目的元组:框架对象,文件名,当前行的行号,函数名称,来自源的上下文行列表代码,以及该列表中当前行的索引。
traceback
模块的
A&#34;预处理&#34;堆栈跟踪条目是一个4元组(文件名,行号,函数名,文本)
因此,不同之处在于帧记录还包括帧对象和一些上下文行,而回溯仅包括调用堆栈中各行的文本(即导致{{1}的调用呼叫)。
如果您只想打印回溯,可以使用extract_stack
中的堆栈。如文档所示,这是为了向用户显示而处理的信息。如果您想对调用堆栈实际执行任何操作(例如,从调用帧读取变量),则需要从traceback
访问框架对象。