FAQ
This is a recurrent situation: I want to initialize a whole bunch
of local variables in a uniform way, but after initialization, I
need to do different things with the various variables.

What I end up doing is using a dict:

d = dict()
for v in ('spam', 'ham', 'eggs'):
d[v] = init(v)

foo(d['spam'])
bar(d['ham'])
baz(d['eggs'])



This is fine, but I'd like to get rid of the tedium of typing all
those extra d['...']s.

I.e., what I would *like* to do is something closer to this:

d = locals()
for v in ('spam', 'ham', 'eggs'):
d[v] = init(v)

foo(spam)
bar(ham)
baz(eggs)

...but this results in errors like "NameError: global name 'spam' is
not defined".

But the problem is deeper than the fact that the error above would
suggest, because even this fails:

spam = ham = eggs = None
d = locals()
for v in ('spam', 'ham', 'eggs'):
d[v] = init(v)

foo(spam) # calls foo(None)
bar(ham) # calls bar(None)
baz(eggs) # calls baz(None)


In other words, setting the value of locals()['x'] does not set
the value of the local variable x.

I also tried a hack using eval:

for v in ('spam', 'ham', 'eggs'):
eval "%s = init('%s')" % (v, v)

but the "=" sign in the eval string resulted in a "SyntaxError:
invalid syntax".

Is there any way to use a loop to set a whole bunch of local
variables (and later refer to these variables by their individual
names)?

TIA!

kj

Search Discussions

  • Bruno Desthuilliers at Sep 30, 2010 at 5:36 pm

    On 30 sep, 19:07, kj wrote:
    This is a recurrent situation: I want to initialize a whole bunch
    of local variables in a uniform way, but after initialization, I
    need to do different things with the various variables.

    What I end up doing is using a dict:

    d = dict()
    for v in ('spam', 'ham', 'eggs'):
    ? ? d[v] = init(v)

    foo(d['spam'])
    bar(d['ham'])
    baz(d['eggs'])

    This is fine, but I'd like to get rid of the tedium of typing all
    those extra d['...']s.

    I.e., what I would *like* to do is something closer to this:

    d = locals()
    for v in ('spam', 'ham', 'eggs'):
    ? ? d[v] = init(v)

    foo(spam)
    bar(ham)
    baz(eggs)

    ...but this results in errors like "NameError: global name 'spam' is
    not defined".

    But the problem is deeper than the fact that the error above would
    suggest, because even this fails:

    spam = ham = eggs = None
    d = locals()
    for v in ('spam', 'ham', 'eggs'):
    ? ? d[v] = init(v)
    The local namespace is not implemented as a dict - locals() only
    returns a dict representation of it, so updating this dict has no
    effect on the local namespace. This is documented FWIW.
    I also tried a hack using eval:

    for v in ('spam', 'ham', 'eggs'):
    ? ? eval "%s = init('%s')" % (v, v)

    but the "=" sign in the eval string resulted in a "SyntaxError:
    invalid syntax".
    eval only accepts expressions. You'd need exec here - but that's a bit
    ugly.
  • MRAB at Sep 30, 2010 at 5:40 pm

    On 30/09/2010 18:07, kj wrote:


    This is a recurrent situation: I want to initialize a whole bunch
    of local variables in a uniform way, but after initialization, I
    need to do different things with the various variables.

    What I end up doing is using a dict:

    d = dict()
    for v in ('spam', 'ham', 'eggs'):
    d[v] = init(v)

    foo(d['spam'])
    bar(d['ham'])
    baz(d['eggs'])



    This is fine, but I'd like to get rid of the tedium of typing all
    those extra d['...']s.

    I.e., what I would *like* to do is something closer to this:

    d = locals()
    for v in ('spam', 'ham', 'eggs'):
    d[v] = init(v)

    foo(spam)
    bar(ham)
    baz(eggs)

    ...but this results in errors like "NameError: global name 'spam' is
    not defined".

    But the problem is deeper than the fact that the error above would
    suggest, because even this fails:

    spam = ham = eggs = None
    d = locals()
    for v in ('spam', 'ham', 'eggs'):
    d[v] = init(v)

    foo(spam) # calls foo(None)
    bar(ham) # calls bar(None)
    baz(eggs) # calls baz(None)


    In other words, setting the value of locals()['x'] does not set
    the value of the local variable x.

    I also tried a hack using eval:

    for v in ('spam', 'ham', 'eggs'):
    eval "%s = init('%s')" % (v, v)

    but the "=" sign in the eval string resulted in a "SyntaxError:
    invalid syntax".

    Is there any way to use a loop to set a whole bunch of local
    variables (and later refer to these variables by their individual
    names)?
    The handling of local variables in CPython is optimised, so changing
    locals() won't have any effect, as you discovered.

    An alternative is to create a namespace in an instance of a class and
    then add attributes to it:

    class Namespace(object):
    pass

    n = Namespace()
    for v in ('spam', 'ham', 'eggs'):
    setattr(n, v, init(v))

    foo(n.spam)
    bar(n.ham)
    baz(n.eggs)
  • Arnaud Delobelle at Sep 30, 2010 at 6:41 pm

    MRAB <python at mrabarnett.plus.com> writes:
    On 30/09/2010 18:07, kj wrote:



    This is a recurrent situation: I want to initialize a whole bunch
    of local variables in a uniform way, but after initialization, I
    need to do different things with the various variables.

    What I end up doing is using a dict:

    d = dict()
    for v in ('spam', 'ham', 'eggs'):
    d[v] = init(v)

    foo(d['spam'])
    bar(d['ham'])
    baz(d['eggs'])



    This is fine, but I'd like to get rid of the tedium of typing all
    those extra d['...']s.

    I.e., what I would *like* to do is something closer to this:

    d = locals()
    for v in ('spam', 'ham', 'eggs'):
    d[v] = init(v)

    foo(spam)
    bar(ham)
    baz(eggs)

    ...but this results in errors like "NameError: global name 'spam' is
    not defined".

    But the problem is deeper than the fact that the error above would
    suggest, because even this fails:

    spam = ham = eggs = None
    d = locals()
    for v in ('spam', 'ham', 'eggs'):
    d[v] = init(v)

    foo(spam) # calls foo(None)
    bar(ham) # calls bar(None)
    baz(eggs) # calls baz(None)


    In other words, setting the value of locals()['x'] does not set
    the value of the local variable x.

    I also tried a hack using eval:

    for v in ('spam', 'ham', 'eggs'):
    eval "%s = init('%s')" % (v, v)

    but the "=" sign in the eval string resulted in a "SyntaxError:
    invalid syntax".

    Is there any way to use a loop to set a whole bunch of local
    variables (and later refer to these variables by their individual
    names)?
    The handling of local variables in CPython is optimised, so changing
    locals() won't have any effect, as you discovered.

    An alternative is to create a namespace in an instance of a class and
    then add attributes to it:

    class Namespace(object):
    pass

    n = Namespace()
    for v in ('spam', 'ham', 'eggs'):
    setattr(n, v, init(v))

    foo(n.spam)
    bar(n.ham)
    baz(n.eggs)
    Note that "exec" can be used:
    def init(name):
    ... return "init " + name
    ...
    def foo():
    ... for name in "bar", "baz":
    ... exec "%s = init(name)" % name
    ... print bar
    ... print baz
    ...
    foo()
    init bar
    init baz

    Not that I can think of a reason to do this :)

    --
    Arnaud
  • Alex23 at Oct 1, 2010 at 12:49 am

    kj wrote:
    This is a recurrent situation: I want to initialize a whole bunch
    of local variables in a uniform way, but after initialization, I
    need to do different things with the various variables.

    What I end up doing is using a dict:

    d = dict()
    for v in ('spam', 'ham', 'eggs'):
    ? ? d[v] = init(v)

    foo(d['spam'])
    bar(d['ham'])
    baz(d['eggs'])

    This is fine, but I'd like to get rid of the tedium of typing all
    those extra d['...']s.
    Here's an approach that uses a decorator. It requires strings to be
    passed, so it's not an exact fit for your requirement, but it's very
    straightforward:

    d = dict(
    spam = 1,
    ham = 2,
    eggs = 3
    )

    def argdispatch(func):
    def _wrapper(*args):
    args = [d[k] for k in args if k in d]
    return func(*args)
    return _wrapper

    @argdispatch
    def foo(x):
    print x

    @argdispatch
    def bar(x):
    print x*2
    foo('spam')
    1
    bar('spam')
    2
    >>>

    With a good editor, it should even take care of one of the quotes for
    you ;)
  • Fuzzyman at Oct 1, 2010 at 12:12 pm

    On Sep 30, 6:07?pm, kj wrote:
    This is a recurrent situation: I want to initialize a whole bunch
    of local variables in a uniform way, but after initialization, I
    need to do different things with the various variables.

    What I end up doing is using a dict:

    d = dict()
    for v in ('spam', 'ham', 'eggs'):
    ? ? d[v] = init(v)

    foo(d['spam'])
    bar(d['ham'])
    baz(d['eggs'])

    This is fine, but I'd like to get rid of the tedium of typing all
    those extra d['...']s.

    I.e., what I would *like* to do is something closer to this:

    d = locals()
    for v in ('spam', 'ham', 'eggs'):
    ? ? d[v] = init(v)

    foo(spam)
    bar(ham)
    baz(eggs)

    ...but this results in errors like "NameError: global name 'spam' is
    not defined".

    But the problem is deeper than the fact that the error above would
    suggest, because even this fails:

    spam = ham = eggs = None
    d = locals()
    for v in ('spam', 'ham', 'eggs'):
    ? ? d[v] = init(v)

    foo(spam) # calls foo(None)
    bar(ham) ?# calls bar(None)
    baz(eggs) # calls baz(None)

    In other words, setting the value of locals()['x'] does not set
    the value of the local variable x.

    I also tried a hack using eval:

    for v in ('spam', 'ham', 'eggs'):
    ? ? eval "%s = init('%s')" % (v, v)

    but the "=" sign in the eval string resulted in a "SyntaxError:
    invalid syntax".

    Is there any way to use a loop to set a whole bunch of local
    variables (and later refer to these variables by their individual
    names)?
    One way:

    import sys
    module = sys.modules[__name__]

    for entry in ('spam', 'eggs', 'ham'):
    setattr(module, entry, 'some value')


    Michael Foord
  • Bruno Desthuilliers at Oct 1, 2010 at 2:40 pm

    On 1 oct, 14:12, Fuzzyman wrote:
    On Sep 30, 6:07?pm, kj wrote:


    This is a recurrent situation: I want to initialize a whole bunch
    of local variables in a uniform way, but after initialization, I
    need to do different things with the various variables.
    What I end up doing is using a dict:
    d = dict()
    for v in ('spam', 'ham', 'eggs'):
    ? ? d[v] = init(v)
    foo(d['spam'])
    bar(d['ham'])
    baz(d['eggs'])
    This is fine, but I'd like to get rid of the tedium of typing all
    those extra d['...']s.
    I.e., what I would *like* to do is something closer to this:
    d = locals()
    for v in ('spam', 'ham', 'eggs'):
    ? ? d[v] = init(v)
    foo(spam)
    bar(ham)
    baz(eggs)
    ...but this results in errors like "NameError: global name 'spam' is
    not defined".
    But the problem is deeper than the fact that the error above would
    suggest, because even this fails:
    spam = ham = eggs = None
    d = locals()
    for v in ('spam', 'ham', 'eggs'):
    ? ? d[v] = init(v)
    foo(spam) # calls foo(None)
    bar(ham) ?# calls bar(None)
    baz(eggs) # calls baz(None)
    In other words, setting the value of locals()['x'] does not set
    the value of the local variable x.
    I also tried a hack using eval:
    for v in ('spam', 'ham', 'eggs'):
    ? ? eval "%s = init('%s')" % (v, v)
    but the "=" sign in the eval string resulted in a "SyntaxError:
    invalid syntax".
    Is there any way to use a loop to set a whole bunch of local
    variables (and later refer to these variables by their individual
    names)?
    One way:

    import sys
    module = sys.modules[__name__]

    for entry in ('spam', 'eggs', 'ham'):
    ? ? setattr(module, entry, 'some value')
    Only works on globals - which you can already set using globals()
    IIRC.
  • Lawrence D'Oliveiro at Oct 5, 2010 at 12:42 am
    In message <mailman.1218.1285868424.29448.python-list at python.org>, MRAB
    wrote:
    An alternative is to create a namespace in an instance of a class and
    then add attributes to it:

    class Namespace(object):
    pass

    n = Namespace()
    for v in ('spam', 'ham', 'eggs'):
    setattr(n, v, init(v))

    foo(n.spam)
    bar(n.ham)
    baz(n.eggs)
    I?d add my vote to this. If you want to hack a namespace, make your own,
    don?t try to mess with the unqualified local or global namespaces.

    And as above, you can use a short prefix to save typing.
  • Steve Howell at Oct 5, 2010 at 1:40 am

    On Sep 30, 10:07?am, kj wrote:
    This is a recurrent situation: I want to initialize a whole bunch
    of local variables in a uniform way, but after initialization, I
    need to do different things with the various variables.
    I'm curious what a typical use case for this is. It seems funny to
    have variables that are initialized the same way, yet which are not in
    a collection.
    What I end up doing is using a dict:

    d = dict()
    for v in ('spam', 'ham', 'eggs'):
    ? ? d[v] = init(v)

    foo(d['spam'])
    bar(d['ham'])
    baz(d['eggs'])
    If you really want to get vars into the local namespace after the
    initialization step, you can do something like this:

    spam, ham, eggs = [init(v) for v in ['spam', 'ham', 'eggs']]

    It's certainly awkward and brittle, but it lets you trade off re-
    typing init() and d[] for another type of lexical duplication.

    I wonder if you are either a) trying too hard to work around harmless
    duplication or b) dealing with a duplication smell that actually runs
    deeper than namespace hacking can fix.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
grouppython-list @
categoriespython
postedSep 30, '10 at 5:07p
activeOct 5, '10 at 1:40a
posts9
users8
websitepython.org

People

Translate

site design / logo © 2022 Grokbase