En Thu, 11 Mar 2010 21:03:07 -0300, F?lix-Antoine Fortin
Post by Félix-Antoine FortinPost by Alf P. SteinbachPost by Félix-Antoine Fortin# Experience with frame
import sys
import inspect
stack = inspect.stack()
print "foo frame : " + str(hex(id(sys._getframe())))
inspect.stack()
print "foo2 frame : " + str(hex(id(sys._getframe())))
print "bar frame : " + str(hex(id(sys._getframe())))
foo()
foo()
foo2()
foo2()
bar()
bar()
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
Post by Félix-Antoine FortinPost by Alf P. SteinbachPost by Félix-Antoine FortinOr 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.
Post by Félix-Antoine FortinActually, what you said about lifetime applies here too. Here is
another quick
import sys
import inspect
stack = inspect.stack()
return sys._getframe()
stack = inspect.stack()
del stack
return sys._getframe()
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)
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