NB: This question assumes Python 2.7.3.
I'm looking for a sane approach to dynamically modify a function's local namespace, preferably in a way that adds the least clutter to the body function.
What I have in mind would look something like this:
import os
from namespace_updater import update_locals
def somefunc(x, y, z):
# ...
# ...
# this and that
# ...
# ...
if os.environ.get('FROBNICATE'):
from frobnitz import frobnicate
update_locals(frobnicate(locals()))
#
# life goes on, possibly with duly frobnicated local variables...
# ...
# ...
# ...
Thanks!
PS: Below are approaches that don't work.
The most naive approach to this would be something like:
locals().update(new_locals(locals())
...but the documentation for locals()
very explicitly warns against relying on such voodoo to modify local variables, so please do not submit this as an answer (unless you can make an excellent case for disregarding the documentation's warning).
Next in the naivete scale is something like
for k, v in new_locals(locals()).items():
exec ('%s = v' % k)
AFAICT, such code cannot be "out of the way" (i.e., it has to be in the body of the function), which is not ideal. But the real deal-breaker is that the exec ('%s = v' % k)
hack can lead to some bizarre bugs.
When I write "bizarre bugs" what I mean is "bugs that look bizarre to someone with as tenuous a grasp of exec ('%s = v' % k)
as mine". How tenuous is my grasp of this hack? To answer this, consider the script below. It has three variants: (1) exactly as shown; (2) after deleting the leading #
of line 18; (3) after deleting the first #
in both lines 15 and 18 (i.e. for this variant, no code is commented out). I could have not predicted the behavior of variants (2) and (3) of this script. I could not have even predicted with more than a 50% confidence the behavior of variant (1). That's how tenuous my grasp of the exec ('%s = v' % k)
hack. Unless you can confidently and correctly predict how the three variants of this script will behave (under python 2.7), it is safe to say that your grasp of the situation is about as tenuous as mine, and you probably should stay clear of exec ('%s = v' % k)
too.
x = 'global x' # 01
y = 'global y' # 02
def main(): # 03
x = 'local x' # 04
y = 'local y' # 05
run(locals()) # 06
print 'OK' # 07
return 0 # 08
# 09
def run(namespace): # 10
global y # 11
print locals().keys() # 12
for k, v in namespace.items(): # 13
print '%s <- %r' % (k, v) # 14
exec ('%s = v' % k) #in locals() # 15
print locals().keys() # 16
x = x # 17
#z = lambda: k # 18
print x # 19
print y # 20
# 21
exit(main()) # 22