Symbols as parameters?

George Sakkis george.sakkis at gmail.com
Sun Jan 24 19:11:07 CET 2010


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.

George



More information about the Python-list mailing list