views:

563

answers:

6

Say you have,

foo = 'bar'
d = {'a-key':'a-value'}

And you want

d = {'a-key':'a-value','foo':'bar'}
e = {'foo':foo}

I know you can do,

d['foo'] = foo

#Either of the following for e
e = {'foo':foo}
e = dict(foo=foo)

But, in all these way to add the variable foo to dict, I have had to use the word foo twice; once to indicate the key and once for its value.

It seems wasteful to me to use foo twice. Is there a simpler way, in which you can tell python "Add this variable to the dictionary with its name as the key and its value as the value"?

+1  A: 

You can use:

name = 'foo'
d[name] = vars[name]

I don't see the difference between your d and e cases: both set 'foo' to the value of foo.

It gets trickier if you want to bury this in a function:

def add_variable(d, name):
    # blah

because then it has to use inspect to start poking around in frames.

This sounds like a larger problem that might have a nicer solution if you wanted to describe it to us. For example, if the problem is that you don't care just about foo, but in fact, a whole slew of local variables, then maybe you want something like:

d.update(locals())

which will copy the names and value of all the local variables into d.

Ned Batchelder
Ned: This is a common django pattern, return render_to_resp('template', {'a':a, 'b":b, 'c':c}). Wont it be better if I could do, render_to_resp('template', func(a, b, c, d))
uswaretech
Exactly: What about: `render_to_response('template', locals())`?
Ned Batchelder
Works, but to allow a possibly unsafe template access to *all* your local variables may not be desirable.
Wim
+3  A: 

you can do something like this

def add_dry_foo(d, namespace, fooName):
    d[fooName] = namespace[fooName]

foo = 'oh-foo'
d = {}
add_dry_foo(d, locals(), 'foo')
print d
Anurag Uniyal
A: 

You could use eval, although I'm not sure that I'd recommend it.

>>> d = dict()
>>> foo = 'wibble'
>>> def add(d, name):
        d[name] = eval(name)


>>> add(d, 'foo')
>>> d
{'foo': 'wibble'}

Edit: I should point out why I don't recommend "eval". What happens if you do something like this? (from: http://mail.python.org/pipermail/tutor/2005-November/042854.html)

>>> s = "(lambda loop: loop(loop)) (lambda self: self(self))"
>>> add(d, s)

Traceback (most recent call last):
  File "<pyshell#54>", line 1, in <module>
    add(d, s)
  File "<pyshell#43>", line 2, in add
    d[name] = eval(name)
  File "<string>", line 1, in <module>
  File "<string>", line 1, in <lambda>
  File "<string>", line 1, in <lambda>
  ...
  File "<string>", line 1, in <lambda>
RuntimeError: maximum recursion depth exceeded
Rod Hyde
+1  A: 

Actutally using foo twice is remarkably common in python programs. It is used extensively for passing on arguments eg

def f(foo, bar):
    g(foo=foo)

Which is a specialised case of the dictionary manipulations in your question.

I don't think there is a way of avoiding it without resorting to magic, so I think you'll have to live with it.

Nick Craig-Wood
Yes. It is definitely common, and I think about avoiding it, each time. My question, in general covers this general repetition too.
Lakshman Prasad
+1  A: 

To add all the local variables to a dict you can do:

d.update(locals())

The same works for function calls:

func(**locals())

Note that depending on where you are locals() might of course contain stuff that should not end up in the dict. So you could implement a filter function:

def filtered_update(d, namespace):
    for key, value in namespace.items():
        if not key.startswith('__'):
            d[key] = value

filtered_update(d, locals())

Of course the Python philosophy is "explicit is better than implicit", so generally I would walk the extra mile and do this kind of stuff by hand (otherwise you have to be careful about what goes on in your local namespace).

nikow
+1  A: 

If you don't want to pass all of locals() (which may be a security risk if you don't fully trust the function you're sending the data too), a one-line answer could be this:

dict([ (var, locals()[var]) for var in ['foo', 'bar'] ])

or in Python 3.0 this would become possible:

{ var: locals()[var] for var in ['foo', 'bar'] }

Wim
+1 for the dict comprehension of Py3k
Lakshman Prasad