inspect.stack() and frame

Gabriel Genellina gagsl-py2 at yahoo.com.ar
Fri Mar 12 01:11:44 EST 2010


En Thu, 11 Mar 2010 21:03:07 -0300, Félix-Antoine Fortin  
<felix.antoine.fortin at gmail.com> escribió:
> On Mar 11, 6:22 pm, "Alf P. Steinbach" <al... at start.no> wrote:
>> * F lix-Antoine Fortin:
>>
>> > Given this code :
>> > # Experience with frame
>> > import sys
>> > import inspect
>>
>> > def foo():
>> >     stack = inspect.stack()
>> >     print "foo frame : " + str(hex(id(sys._getframe())))
>>
>> > def foo2():
>> >     inspect.stack()
>> >     print "foo2 frame : " + str(hex(id(sys._getframe())))
>>
>> > def bar():
>> >     print "bar frame : " + str(hex(id(sys._getframe())))
>>
>> > foo()
>> > foo()
>>
>> > foo2()
>> > foo2()
>>
>> > bar()
>> > bar()
>>
>> > Output example :
>> > foo frame : 0x84d2c0
>> > foo frame : 0x844bf0
>> > foo2 frame : 0x898c90
>> > foo2 frame : 0x898c90
>> > bar frame : 0x898f70
>> > bar frame : 0x898f70
>>
>> > Why are the ids (address) of the frame for each foo call not the same?
>>
>> You're dealing with Python objects. You're not dealing with the  
>> computer's
>> machine stack. Whether you get the same id for two objects whose  
>> lifetimes don't
>> overlap depends on the implementation's memory and id allocation  
>> strategy.
>>
>
> Okay, I thought I got that when I read the id documentation, but now I
> get it.
> So the only to compare two ids, is by making sure their lifetimes
> overlap. In
> this case, instead of keeping the ids, I have to keep a reference on
> the frame
> to make sure it is still alive when I will compare it with a second
> one.

The best way to compare object identities is using the 'is' operator: `a  
is b` returns true if and only if after evaluating both operands they are  
the very same object.
id() may be misleading if you are not careful:

py> id([]) == id([])
True
py> [] is []
False

>> > Or why the call to "stack = inspect.stack()" change the address of the
>> > frame?
>>
>> Does it?
>
> Yeah it does... I always get N different id when I run foo() N times
> in a row.

Think again after reading the response below.

> Actually, what you said about lifetime applies here too. Here is
> another quick
> snippet :
>
> import sys
> import inspect
>
> def foo():
>     stack = inspect.stack()
>     return sys._getframe()
>
> def foo2():
>     stack = inspect.stack()
>     del stack
>     return sys._getframe()
>
> def bar():
>         inspect.stack()
>         return sys._getframe()
>
> frame_foo = foo()
> frame_foo2 = foo2()
> frame_bar = bar()
>
> print sys.getrefcount(frame_foo)
> print sys.getrefcount(frame_foo2)
> print sys.getrefcount(frame_bar)
>
> Output :
> 3
> 2
> 2
>
> So it seems that there is one more reference to the foo frame because
> only because of "stack = inspect.stack()", so its lifetime isn't done
> contrary to foo2 and bar frame, and the frame id of a foo frame is
> different for each call.
>
> Now, what is keeping a reference on foo frame?

The foo frame keeps a reference to the 'stack' local variable (in its  
f_locals attribute), and 'stack' keeps a reference to the current frame  
too.
This doesn't happen neither in foo2() nor bar(), where the local array is  
empty. inspect.stack() isn't special: any other reference to the current  
frame would have the same effect.

Let's examine the simple example above:

py> id([]) == id([])
True

Python creates an empty list, takes its id, and discards the list. The  
list object is then ready to be re-used again (the interpreter keeps a  
list of free objects for many common types), so the right-hand side gets  
the very same list.

The same thing happens with the frame object in your first examples foo2()  
and bar(): the frame object is discarded after leaving the function, and  
is ready to be used again in the next call. But foo() creates a circular  
reference - the frame object is still alive after leaving the first call,  
so the second call must use a new frame. (The garbage collector will,  
eventually, break the cycle and free those objects, but not very soon).

-- 
Gabriel Genellina




More information about the Python-list mailing list