If you want X, you know where to find it (was Re: do...until wisdom needed...)
Alex Martelli
aleaxit at yahoo.com
Thu Apr 19 04:15:16 EDT 2001
"Andrew Dalke" <dalke at acm.org> wrote in message
news:9bm47r$qo2$1 at slb5.atl.mindspring.net...
[snip]
> >(Is there a way in Python of finding local
> >variables by name on the Python stack so that a procedure can get and
> >set variables in the caller's environment? If so, you could do it,
> >but it would be pretty ugly.)
>
> Yes and no. Python deliberately makes it hard. You need
> to raise an exception and look up the stack frames. There
In 2.1, sys._getframe (to "be used for internal and
specialized purposes only") provides a somewhat handier
alternative to the classic raise-and-look-up idiom.
But I don't think this has changed what you can
actually _do_ once you've got the caller's frame
object -- "see, but not touch", more or less.
Consider, for example:
import sys
if hasattr(sys, '_getframe'):
def callerlocals():
return sys._getframe(2).f_locals
else:
def callerlocals():
try: raise 'catch me'
except: return sys.exc_traceback.tb_frame.f_back.f_back.f_locals
any = 'pass'
def f():
x = 23
print x
g(x=24)
exec any
print x
g(y=37)
exec any
print x,y
def g(**kws):
print callerlocals()
callerlocals().update(kws)
print callerlocals()
f()
In both 2.0 and 2.1, this outputs:
23
{'x': 23}
{'x': 23}
23
{'x': 23}
{'x': 23, 'y': 37}
23 37
I.e., the "exec 'pass'" trick has allowed the addition
of a new binding for y, but not the rebinding of x
anyway. If you comment out the exec statements, then
f's attempt to access y fails:
23
{'x': 23}
{'x': 23}
23
{'x': 23}
{'x': 23, 'y': 37}
23
Traceback (most recent call last):
File "caller.py", line 28, in ?
f()
File "caller.py", line 20, in f
print x,y
NameError: global name 'y' is not defined
The dictionary object has allowed the update (sort
of: it has allowed the addition of y->37, but not
the rebinding of x->23 to x->24), but the code is
not looking at that dictionary to fetch 'y' -- the
optimizer, absent an exec statement, having decided
that 'y' is a global, not a local, variable, it
has generated bytecode to fetch a global specifically.
Alex
More information about the Python-list
mailing list