[Python-Dev] frame.f_locals is writable
Brett C.
bac at OCF.Berkeley.EDU
Thu Jan 13 22:50:24 CET 2005
Shane Holloway (IEEE) wrote:
> For a little background, I'm working on making an edit and continue
> support in python a little more robust. So, in replacing references to
> unmodifiable types like tuples and bound-methods (instance or class), I
> iterate over gc.get_referrers.
>
> So, I'm working on frame types, and wrote this code::
>
> def replaceFrame(self, ref, oldValue, newValue):
> for name, value in ref.f_locals.items():
> if value is oldValue:
> ref.f_locals[name] = newValue
> assert ref.f_locals[name] is newValue
>
>
> But unfortunately, the assert fires. f_locals is writable, but not
> modifiable. I did a bit of searching on Google Groups, and found
> references to a desire for smalltalk like "swap" functionality using a
> similar approach, but no further ideas or solutions.
>
> While I am full well expecting the smack of "don't do that", this
> functionality would be very useful for debugging long-running
> applications. Is this possible to implement in CPython and ports? Is
> there an optimization reason to not do this?
>
So it would be doable, but it is not brain-dead simple if you want to keep the
interface of a dict. Locals, in the frame, are an array of PyObjects (see
PyFrameObject->f_localsplus). When you request f_locals that returns a dict
that was created by a function that takes the array, traverses it, and creates
a dict with the proper names (using PyFrameObject->f_code->co_varnames for the
array offset -> name mapping). The resulting dict gets stored in
PyFrameObject->f_locals. So it is writable as you discovered since it is just
a dict, but it is not used in Python/ceval.c except for IMPORT_STAR; changes
are just never even considered. The details for all of this can be found in
Objects/frameobject.c:PyFrame_FastToLocals() .
The interesting thing is that there is a corresponding PyFrame_LocalsToFast()
function that seems to do what you want; it takes the dict in
PyFrameObject->f_locals and propogates the changes into
PyFrameObject->f_localsplus (or at least seems to; don't have time to stare at
the code long enough to make sure it does that exactly). So the functionality
is there (and is in the API even). It just isn't called explicitly except in
two points in Python/ceval.c where you can't get at it. =)
As to making changes to f_locals actually matter would require either coming up
with a proxy object that is stored in f_locals instead of a dict and
dynamically grab everything from f_localsplus as needed. That would suck for
performance and be a pain to keep the dict API. So you can count that out.
Other option would be to add a function that either directly modified single
values in f_localsplus, a function that takes a dict and propogates the values,
or a function that just calls PyFrame_LocalsToFast() .
Personally I am against this, but that is because you would single-handedly
ruin my master's thesis and invalidate any possible type inferencing one can do
in Python without some semantic change. But then again my thesis shows that
amount of type inferencing is not worth the code complexity so it isn't totally
devastating. =)
And you are right, "don't do that". =)
Back to the putrid, boggy marsh of JavaLand for me...
-Brett
More information about the Python-Dev
mailing list