By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
457,696 Members | 1,486 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 457,696 IT Pros & Developers. It's quick & easy.

Injecting new names into the above frame

P: n/a
Dear Pythoners,

I know this will probably be perceived as 'evil voodoo', and fair
enough: it probably is. I guess it is unpythonic.

... but I want to know how to do it anyway - mostly for my own
interest.

Consider the following snippet of code:

---
def Get( *names ):
if not names: return None

frame = sys._getframe(1)
prevFrameLocals = frame.f_locals

for name in names:
prevFrameLocals[ name ] = FetchObjectNamed( name )

Get("a", "b", "c")

print a, b, c
---

FetchObjectNamed() is an arbitrary function which takes a string and
returns an object it got from some store somewhere.

This works fine at the module level, because names in the locals/
globals dictionary can be played with in this way. The idea is to save
lots of typing, i.e.

a, b, c = Get("a","b","c")

...gets frustrating after much typing for many objects with long names.
This is just an example, there are other instances I have where it
would be nice to inject names into the frame above.

Of course, we hit a road block when we call 'Get' from a function
rather than a module, because the locals dictionary does not get
copied back into the code object automatically, so we have to add this
snippet before the Get() function returns:

from ctypes import pythonapi, py_object, c_int
pythonapi.PyFrame_LocalsToFast( py_object( frame ), 1 )

This copies back the names into the code object, and works fine.. that
is, if the names already exist within the code object.

def MyFunction():
a = None
Get("a")
print a # Works
Get("b")
print b # Name error, b is undefined

Is there any way for Get() to define a new variable within
MyFunction's code object? Or is there any programmatic way to, at
runtime, insert new names into functions?

I don't care how hacky it is and whether it requires making calls to
python's internals with ctypes - maybe the whole code object needs to
be replaced? is it even possible to do that when the Get() function is
about to return to this new code object?

Cheers,

- Peter
Sep 12 '08 #1
Share this Question
Share on Google+
4 Replies


P: n/a
Peter Waller wrote:
Dear Pythoners,

I know this will probably be perceived as 'evil voodoo', and fair
enough: it probably is. I guess it is unpythonic.

.. but I want to know how to do it anyway - mostly for my own
interest.
Well, if you're really just asking out of curiosity, it should be
sufficient to tell you that this is not possible.
[...] we have to add this
snippet before the Get() function returns:

from ctypes import pythonapi, py_object, c_int
pythonapi.PyFrame_LocalsToFast( py_object( frame ), 1 )

This copies back the names into the code object, and works fine.. that
is, if the names already exist within the code object.

def MyFunction():
a = None
Get("a")
print a # Works
Get("b")
print b # Name error, b is undefined
The answer to why this doesn't work lies in the disassembly of that
function:
0 LOAD_CONST 0 (0)
3 STORE_FAST 0 (0)
6 LOAD_GLOBAL 1 (1)
9 LOAD_CONST 1 (1)
12 CALL_FUNCTION 1
15 POP_TOP
16 LOAD_FAST 0 (0) <- This is a
19 PRINT_ITEM
20 PRINT_NEWLINE
21 LOAD_GLOBAL 1 (1)
24 LOAD_CONST 2 (2)
27 CALL_FUNCTION 1
30 POP_TOP
31 LOAD_GLOBAL 2 (2) <- This is b
34 PRINT_ITEM
35 PRINT_NEWLINE
36 LOAD_CONST 0 (0)
39 RETURN_VALUE

Since you have an assignment to the name a, a is recognized as a local
name at compile time. b is not recognized as a local name at compile
time, so even if you inject a value for b into the locals dictionary,
the byte code still looks up the value as a global name.
Is there any way for Get() to define a new variable within
MyFunction's code object? Or is there any programmatic way to, at
runtime, insert new names into functions?
Not without making fundamental changes to Python itself. The fact that
this isn't possible is a feature, in my opinion. I like the fact that I
can call a function and be *absolutely certain* that it's not going to
pollute my local namespace.

Hope this helps,

--
Carsten Haese
http://informixdb.sourceforge.net
Sep 12 '08 #2

P: n/a
On Sep 12, 2:30*pm, Carsten Haese <carsten.ha...@gmail.comwrote:
>
The answer to why this doesn't work lies in the disassembly of that
function:
This makes me want to ask: is it difficult to modify a function's
code? Even if it weren't possible whilst the function was executing
(because then I would be returning to a function I just created, I
guess?) Could I make another function which converted this LOAD_GLOBAL
to LOAD_FAST?

I agree that in general a function should have no side effects and I
would like to know exactly what it is going to do, and that what I'm
doing is unpythonic.

My curiosity extends because I would like to get to know a bit more
about python's internals. My gut tells me there has to be a way to
achieve what I'm after - even if it the result is extremely ugly.
Maybe it might involve applying a decorator to functions who use this
functionality, who change the code so that these calls work?

Cheers for your reply,

- Pete
Sep 13 '08 #3

P: n/a
On Sep 13, 1:35*pm, Peter Waller <peter.wal...@gmail.comwrote:
This makes me want to ask: is it difficult to modify a function's
code?
No, it is not difficult. Look at the byteplay module:
it makes possible all kinds of dirty hacks.
Sep 13 '08 #4

P: n/a
Why don't you use import and __import__() ? - They seem designed for such an
application.

I mean, I am not against vicious hacks for the fun of them, but not if they
serve the illusion that what they do can't (easily) be achieved other ways.

Cheers, BB

Peter Waller wrote:
Dear Pythoners,

I know this will probably be perceived as 'evil voodoo', and fair
enough: it probably is. I guess it is unpythonic.

.. but I want to know how to do it anyway - mostly for my own
interest.

Consider the following snippet of code:

---
def Get( *names ):
if not names: return None

frame = sys._getframe(1)
prevFrameLocals = frame.f_locals

for name in names:
prevFrameLocals[ name ] = FetchObjectNamed( name )

Get("a", "b", "c")

print a, b, c
---

FetchObjectNamed() is an arbitrary function which takes a string and
returns an object it got from some store somewhere.

This works fine at the module level, because names in the locals/
globals dictionary can be played with in this way. The idea is to save
lots of typing, i.e.

a, b, c = Get("a","b","c")

..gets frustrating after much typing for many objects with long names.
This is just an example, there are other instances I have where it
would be nice to inject names into the frame above.

Of course, we hit a road block when we call 'Get' from a function
rather than a module, because the locals dictionary does not get
copied back into the code object automatically, so we have to add this
snippet before the Get() function returns:

from ctypes import pythonapi, py_object, c_int
pythonapi.PyFrame_LocalsToFast( py_object( frame ), 1 )

This copies back the names into the code object, and works fine.. that
is, if the names already exist within the code object.

def MyFunction():
a = None
Get("a")
print a # Works
Get("b")
print b # Name error, b is undefined

Is there any way for Get() to define a new variable within
MyFunction's code object? Or is there any programmatic way to, at
runtime, insert new names into functions?

I don't care how hacky it is and whether it requires making calls to
python's internals with ctypes - maybe the whole code object needs to
be replaced? is it even possible to do that when the Get() function is
about to return to this new code object?

Cheers,

- Peter
--
http://mail.python.org/mailman/listinfo/python-list
Sep 13 '08 #5

This discussion thread is closed

Replies have been disabled for this discussion.