What is the difference between a stack and a frame?

2024/11/20 23:33:17

Under what situations would I want to use one over the other?

What is the difference between:

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

And:

>>> import traceback
>>> traceback.extract_stack()
[('<stdin>', 1, '<module>', None)]

Update:

Another:

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

I do not understand the nuances here:

  • Stack Frame
  • Frame Object
  • Stack Trace

update 2, a bit of time since the question was asked, but very relevant

  • Explain the concept of a stack frame in a nutshell
Answer

Alright, since this appears to be more about what stack frames/call stacks are in general, let's go through this:

def f():try:g()except:# WE WILL DO THINGS HEREdef g():h()def h():raise Exception('stuff')#CALL
f()

When we're in h(), there are 4 frames on the call stack.

[top level][f()][g()][h()] #<-- we're here

(if we tried to put more than sys.getrecursionlimit() frames on the stack, we would get a RuntimeError, which is python's version of StackOverflow ;-))

"Outer" refers to everything above us (literally: the direction "up") in the call stack. So in order, g, then f, then the top (module) level. Likewise, "inner" refers to everything downwards in the call stack. If we catch an exception in f(), that traceback object will have references to all of the inner stack frames that were unwound to get us to that point.

def f():try:g()except:import inspectimport sys#the third(last) item in sys.exc_info() is the current traceback objectreturn inspect.getinnerframes(sys.exc_info()[-1])

This gives:

[(<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)]

As expected, the three inner frames f, g, and h. Now, we can take that last frame object (the one from h()) and ask for its outer frames:

[(<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)]

So, there you go, that's all that's going on: we're simply navigating the call stack. For comparison, here's what traceback.extract_stack(f()[-1][0]) gives:

[('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')")]

Notice the inverted order here compared to getouterframes, and the reduced output. In fact, if you squint your eyes, this basically looks like a regular traceback (and hey, it is, with just a little bit more formatting).

Summing up: both inspect.getouterframes and traceback.extract_stack contain all the information to reproduce what you generally see in your everyday traceback; extract_stack just removes the references to the stack frames, since it is very common to no longer need them once you get to the point of formatting your stack trace from-a-given-frame-outwards.

https://en.xdnf.cn/q/26268.html

Related Q&A

Python Reverse Find in String

I have a string and an arbitrary index into the string. I want find the first occurrence of a substring before the index.An example: I want to find the index of the 2nd I by using the index and str.rfi…

Is there a direct approach to format numbers in jinja2?

I need to format decimal numbers in jinja2. When I need to format dates, I call the strftime() method in my template, like this:{{ somedate.strftime(%Y-%m-%d) }}I wonder if there is a similar approach …

Why would running scheduled tasks with Celery be preferable over crontab?

Considering Celery is already a part of the stack to run task queues (i.e. it is not being added just for running crons, that seems an overkill IMHO ).How can its "periodic tasks" feature be …

use a css stylesheet on a jinja2 template

I am making a website using html, css, flask and jinja2.I have a page working on a flask server, the buttons and labels etc. are displayed, but the css stylesheet I have is not loaded in.How would I li…

How to extend Python class init

I have created a base class:class Thing():def __init__(self, name):self.name = nameI want to extend the class and add to the init method so the that SubThing has both a name and a time property. How d…

type hint for an instance of a non specific dataclass

I have a function that accepts an instance of any dataclass. what would be an appropriate type hint for it ?havent found something official in the python documentation this is what I have been doing, …

Is there a static constructor or static initializer in Python?

Is there such a thing as a static constructor in Python? How do I implement a static constructor in Python?Here is my code... The __init__ doesnt fire when I call App like this. The __init__ is not…

What does this - in jinja2 template engine do?

I am learning jinja2 because Google App Engine recommends it.I found this example on Wikipedia: http://en.wikipedia.org/wiki/Jinja_%28template_engine%29{%- for item in item_list %}{{ item }}{% if not l…

When to apply(pd.to_numeric) and when to astype(np.float64) in python?

I have a pandas DataFrame object named xiv which has a column of int64 Volume measurements. In[]: xiv[Volume].head(5) Out[]: 0 252000 1 484000 2 62000 3 168000 4 232000 Name: Volume, d…

How to change folder names in python?

I have multiple folders each with the name of a person, with the first name(s) first and the surname last. I want to change the folder names so that the surname is first followed by a comma and then t…