Just top-posting for clarity. :-)
<code file="directions.py">
up = "UP"
left = "LEFT"
down = "DOWN"
right = "RIGHT"
</code>
<code file="locals.py">
# This code is not guaranteed to work by the language specification.
# But it is one way to do the solution I presented earlier in the thread.
import sys
def import_from( module_name ):
local_variables = sys._getframe( 1 ).f_locals
m = __import__( module_name, globals(), local_variables, "*" )
for name in local_variables:
if not name.startswith( "_" ):
local_variables[name] = getattr( m, name )
def move( direction ):
print( "Moving " + str( direction ) )
def test():
up = "outerScopeUp"
class using_directions:
(up, left, down, right) = 4*[None]; import_from( "directions" )
move( up )
move( down )
move( left )
move( right )
print( "in the outer scope up is still: " + up )
print( "this should fail:" )
down
test()
</code>
<output pyversions="2.x and 3.x">
Moving UP
Moving DOWN
Moving LEFT
Moving RIGHT
in the outer scope up is still: outerScopeUp
this should fail:
Traceback (most recent call last):
File "locals.py", line 29, in <module>
test()
File "locals.py", line 27, in test
down
NameError: global name 'down' is not defined
</output>
Cheers & hth.,
- Alf
* George Sakkis:
On Jan 22, 8:39 pm, Martin Drautzburg <martin.drautzb...@web.de>
wrote:
Martin Drautzburg wrote:
with scope():
# ...
# use up, down, left, right here
# up, down, left, right no longer defined after the with block exits.
Just looked it up again. It's a cool thing. Too bad my locals() hack
would still be required. The result would be less noisy (and actually
really beautiful) than the decorator implementation though. Thanks
again for pointing this out to me.
Both in your example and by using a context manager, you can get away
with not passing locals() explicitly by introspecting the stack frame.
Here's a context manager that does the trick:
from __future__ import with_statement
from contextlib import contextmanager
import sys
@contextmanager
def enums(*consts):
# 2 levels up the stack to bypass the contextmanager frame
f_locals = sys._getframe(2).f_locals
new_names = set()
reset_locals, updated_locals = {}, {}
for const in consts:
updated_locals[const] = const
if const in f_locals:
reset_locals[const] = f_locals[const]
else:
new_names.add(const)
f_locals.update(updated_locals)
try:
yield
finally:
for name in new_names:
del f_locals[name]
f_locals.update(reset_locals)
if __name__ == '__main__':
def move(aDirection):
print "moving " + aDirection
up = "outerScopeUp"
with enums("up", "down", "left", "right"):
move(up)
move(down)
move(left)
move(right)
print "in the outer scope up is still:", up
print "this should fail:"
down
Of course, as all other attempts to mess with locals() shown in this
thread, this only "works" when locals() is globals(). If you try it
within a function, it fails:
def test():
up = "outerScopeUp"
with enums("up", "down", "left", "right"):
move(up)
move(down)
move(left)
move(right)
print "in the outer scope up is still:", up
print "this should fail:"
down
## XXX: doesn't work within a function
test()
So it's utility is pretty limited; a custom DSL is probably better
suited to your problem.
--
http://mail.python.org/mailman/listinfo/python-list