views:

78

answers:

3

I actually want to create a new local. I know it sounds dubious, but I think I have a nice use case for this. Essentially my problem is that this code throws "NameError: global name 'eggs' is not defined" when I try to print eggs:

def f():
    import inspect
    frame_who_called = inspect.stack()[1][0]
    frame_who_called.f_locals['eggs'] = 123

def g():
    f()
    print(eggs)

g()

I found this old thing: http://mail.python.org/pipermail/python-dev/2005-January/051018.html

Which would mean I might be able to do it using ctypes and calling some secret function, though they only talked about updating a value. But maybe there's an easier way?

+4  A: 

I am highly curious as to your use case. Why on Earth are you trying to poke a new local into the caller's frame, rather than simply doing something like this:

def f():
    return 123

def g():
    eggs = f()
    print(eggs)

After all, you can return a tuple with as many values as you like:

def f():
    return 123, 456, 789

def g():
    eggs, ham, bacon = f()
    print(eggs, ham, bacon)
steveha
Because you might want to poke hundreds of variables in this way. You don't want to do that manually.
liori
Why would you want to poke hundreds of variables? Return a class instance, with hundreds of members. It is less likely to drive you insane, and more importantly, less likely to drive insane anyone else trying to understand and maintain your code in future.
steveha
When making DSLs by extending Python. In this case you already throw away lots of assumptions about code, and place different set of assumptions.
liori
+2  A: 

As Greg Hewgill mentioned in a comment on the question, I answered another question about modifying locals in Python 3, and I'll give a bit of a recap here.

There is a post on the Python 3 bug list about this issue -- it's somewhat poorly documented in the Python 3 manuals. Python 3 uses an array for locals instead of a dictionary like in Python 2 -- the advantage is a faster lookup time for local variables (Lua does this too). Basically, the array is defined at "bytecode-compile-time" and cannot be modified at runtime.

See specifically the last paragraph in Georg Brandl's post on the bug list for finer details about why this cannot (and probably never will) work in Python 3.

Mark Rushakoff
+1  A: 

In Python 2.*, you can get such code to work by defeating the normal optimization of locals:

>>> def g():
...   exec 'pass'
...   f()
...   print(eggs)

The presence of an exec statement causes Python 2 to compile g in a totally non-optimized fashion, so locals are in a dict instead of in an array as they normally would be. (The performance hit can be considerable).

This "de-optimization" does not exist in Python 3, where exec is not a statement any more (not even a keyword, just a function) -- even putting parentheses after it doesn't help...:

>>> def x():
...   exec('a=23')
...   print(a)
... 
>>> x()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in x
NameError: global name 'a' is not defined
>>>

i.e., not even exec can now "create locals" that were not know at def-time (i.e., when the compiler did its pass to turn the function body into bytecode).

Your best bet would be to give up. Second best would be to have your f function inject new names into the caller's globals -- those are still a dict, after all.

Alex Martelli