[SciPy-dev] How to get extensions to affect local state

eric eric at scipy.org
Mon Feb 11 14:22:45 CST 2002


Hey Pearu,

>
> On Fri, 8 Feb 2002, Pat Miller wrote:
>
> <snip>
>
> > It is a bit tricky as you cannot just use python tricks to update
> > the local dictionary for affect:
> >
> > That is if inside weave.inline, it makes a call to locals() (or
> > rather gets it from the caller's frame) you can't make changes.
>
> See http://www.python.org/doc/current/lib/built-in-funcs.html:
> locals()
>      Return a dictionary representing the current local symbol
>      table. Warning: The contents of this dictionary should not be
>      modified; changes may not affect the values of local variables used
>      by the interpreter.

The quote from the manual pertains to Python code, but not to C.  In C, you
can get a hold of the frameobject and access the local variables directly.
After all, this is what the Python interpreter does to set and get local
variables.  I won't argue with the theory that this is not exactly
"sanctioned" behavior, but weave's behavior is already somewhat "outside the
box" of standard Python extensions, so I guess that doesn't bug me much.

> And I think you should not modify locals() dictionary from Python
> C/API either.

Well, should and shouldn't is always a debatable concept. :)  The purpose of
inline is to seamlessly transfer variables into C/C++ code and then back out
so that variable names in Python and C share the same information -- just as
if the C code were actually Python code using different syntax.  The only
way to do this is to be able to write back into the local frame, so we need
this capablility.  If it can be made to do this safely and reliably, then I
don't see an issue.

Fernando has expressed wanting to explicitly return values from weave.inline
instead of having variables flow back out of C into Python.  We could put a
flag into to turn this off if people really want that.

> Actually, there are no tricks needed to get what you want in Python.
> For example,
>
> import sys
> def fun(varname):
>     frame = sys._getframe(1)
>     exec '%s = 7' % (varname) in frame.f_locals
> a = 5
> print a
> fun('a')
> print a
>
> will output
>
> 5
> 7

This will only work in certain situations and is not guaranteed to work in
the future.  Here is an example where it doesn't work:

# module test.py
import sys

a=1

def bob(var):
    frame = sys._getframe(1)
    exec '%s = 7' % (var,) in frame.f_locals

def bob2():
    a = 3
    print a
    bob('a')
    print a

print a
bob('a')
print a
bob2()
# end module

C:\home\ej\wrk\junk\scipy\weave\pm>python test.py
1
7
3
3

So it works when called from the module level, but not when called from
within a function.  Also this approach is extremely slow compared to doing
within the C function, so you'd loose much of the benefit of the things
weave and PyCOD are trying to do.

see ya,
eric






More information about the Scipy-dev mailing list