Symbols as parameters?
Alf P. Steinbach
alfps at start.no
Sun Jan 24 15:14:32 EST 2010
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... at 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.
More information about the Python-list
mailing list