Symbols as parameters?

Alf P. Steinbach alfps at start.no
Sun Jan 24 21:14:32 CET 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