108

Is there an easier way to do this in Python (2.7)?: Note: This isn't anything fancy, like putting all local variables into a dictionary. Just the ones I specify in a list.

apple = 1
banana = 'f'
carrot = 3
fruitdict = {}

# I want to set the key equal to variable name, and value equal to variable value
# is there a more Pythonic way to get {'apple': 1, 'banana': 'f', 'carrot': 3}?

for x in [apple, banana, carrot]:
    fruitdict[x] = x # (Won't work)
atp
  • 30,132
  • 47
  • 125
  • 187
  • 1
    Can the variables be defined in the dict? Like fruitdict = dict(apple=1, banana=2, carrot=3) ? – dr jimbob Oct 19 '10 at 21:27
  • Not really, there's a lot of code for each variable so it'd be unreadable. – atp Oct 19 '10 at 21:33
  • I assume you're aware that you code doesn't do what you the comment says it does? You can't go backwards from objects to names unless you find what you want in a namespace dictionary like locals() You could however write a function that looks up these variables in the namespace dictionary and assigns the values found to that key; see jimbob's answer. – Thomas Oct 20 '10 at 04:35
  • Yep, sorry, I should clarify. – atp Oct 20 '10 at 21:19

12 Answers12

106
for i in ('apple', 'banana', 'carrot'):
    fruitdict[i] = locals()[i]
dr jimbob
  • 17,259
  • 7
  • 59
  • 81
  • 18
    one-line ``dict([(i, locals()[i]) for i in ('apple', 'banana', 'carrot')])`` – dinya Nov 29 '16 at 06:55
  • 7
    While this question is about 2.7, note that the above one-liner does not work in Python 3 because `locals()` apparently points to the scope of the list comprehension. – Roope Jan 31 '19 at 12:53
  • So what's the solution in Python 3? – Dr_Zaszuś Dec 16 '19 at 10:10
  • 1
    @Dr_Zaszuś you set `loc=locals()` before `dict([(i, loc[i]) for in ('apple', 'banana', 'carrot')])`. – bers Jan 17 '20 at 07:40
  • 3
    `{i: loc[i] for i in ('apple', 'banana', 'carrot')}`, no need to create a list and convert it to a dict. – Guimoute Dec 28 '20 at 15:00
23

The globals() function returns a dictionary containing all your global variables.

>>> apple = 1
>>> banana = 'f'
>>> carrot = 3
>>> globals()
{'carrot': 3, 'apple': 1, '__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, 'banana': 'f'}

There is also a similar function called locals().

I realise this is probably not exactly what you want, but it may provide some insight into how Python provides access to your variables.

Edit: It sounds like your problem may be better solved by simply using a dictionary in the first place:

fruitdict = {}
fruitdict['apple'] = 1
fruitdict['banana'] = 'f'
fruitdict['carrot'] = 3
Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • Sorry, I must have edited after you were writing your answer. I only need the variables I specify, not all locals() or globals() – atp Oct 19 '10 at 21:33
  • @Jasie: I added an example of simply using a dictionary in the first place, instead of messing around with variables. – Greg Hewgill Oct 19 '10 at 21:42
10

A one-liner is:-

fruitdict = dict(zip(('apple','banana','carrot'), (1,'f', '3'))
Dantalion
  • 323
  • 1
  • 2
  • 7
3

Here it is in one line, without having to retype any of the variables or their values:

fruitdict.update({k:v for k,v in locals().copy().iteritems() if k[:2] != '__' and k != 'fruitdict'})
2

Well this is a bit, umm ... non-Pythonic ... ugly ... hackish ...

Here's a snippet of code assuming you want to create a dictionary of all the local variables you create after a specific checkpoint is taken:

checkpoint = [ 'checkpoint' ] + locals().keys()[:]
## Various local assigments here ...
var_keys_since_checkpoint = set(locals().keys()) - set(checkpoint)
new_vars = dict()
for each in var_keys_since_checkpoint:
   new_vars[each] = locals()[each]

Note that we explicitly add the 'checkpoint' key into our capture of the locals().keys() I'm also explicitly taking a slice of that though it shouldn't be necessary in this case since the reference has to be flattened to add it to the [ 'checkpoint' ] list. However, if you were using a variant of this code and tried to shortcut out the ['checkpoint'] + portion (because that key was already inlocals(), for example) ... then, without the [:] slice you could end up with a reference to thelocals().keys()` whose values would change as you added variables.

Offhand I can't think of a way to call something like new_vars.update() with a list of keys to be added/updated. So thefor loop is most portable. I suppose a dictionary comprehension could be used in more recent versions of Python. However that woudl seem to be nothing more than a round of code golf.

Jim Dennis
  • 17,054
  • 13
  • 68
  • 116
1

Based on the answer by mouad, here's a more pythonic way to select the variables based on a prefix:

# All the vars that I want to get start with fruit_
fruit_apple = 1
fruit_carrot = 'f'
rotten = 666

prefix = 'fruit_'
sourcedict = locals()
fruitdict = { v[len(prefix):] : sourcedict[v]
              for v in sourcedict
              if v.startswith(prefix) }
# fruitdict = {'carrot': 'f', 'apple': 1}

You can even put that in a function with prefix and sourcedict as arguments.

Arnout
  • 2,927
  • 16
  • 24
0

I think the simplest version might be:

fruit_dict = dict(apple=apple, banana=banana, carrot=carrot) 
dijonkitchen
  • 130
  • 3
  • 9
-1

This question has practically been answered, but I just wanted to say it was funny that you said

This isn't anything fancy, like putting all local variables into a dictionary.

Because it is actually "fancier"

what you want is:

apple = 1
banana = 'f'
carrot = 3
fruitdict = {}

# I want to set the key equal to variable name, and value equal to variable value
# is there a more Pythonic way to get {'apple': 1, 'banana': 'f', 'carrot': 3}?

names= 'apple banana carrot'.split() # I'm just being lazy for this post
items = globals()                    # or locals()

for name in names:
    fruitdict[name] = items[name]

Honestly, what you are doing is just copying items from one dictionary to another.

(Greg Hewgill practically gave the whole answer, I just made it complete)

...and like people suggested, you should probably be putting these in the dictionary in the first place, but I'll assume that for some reason you can't

Terence Honles
  • 834
  • 6
  • 9
  • so I guess I didn't see jimbob's post... practically the same thing, just doesn't call locals/globals more than once – Terence Honles Oct 20 '10 at 00:44
  • I'm don't think calling globals more than once would actually be more efficient. – dr jimbob Oct 21 '10 at 13:27
  • E.g., if you do items = locals(); id(locals()) == id(items) you would get equality. Or if you did items=locals(); b = 3 ; items['b'] it will find the new variable b, since it didn't actually copy the locals dict to items (which would be slower). If you had done items=locals().copy() there may have been a minor difference; but then again the copying step is probably slower than accessing the small number of items from the locals dict. – dr jimbob Oct 21 '10 at 13:33
-2

Not the most elegant solution, and only works 90% of the time:

def vardict(*args):
    ns = inspect.stack()[1][0].f_locals
    retval = {}
    for a in args:
        found = False
        for k, v in ns.items():
            if a is v:
                retval[k] = v
                if found:
                    raise ValueError("Value found in more than one local variable: " + str(a))
                found = True
        if found:
            continue
        if 'self' in ns:
            for k, v in ns['self'].__dict__.items():
                if a is v:
                    retval[k] = v
                    if found:
                        raise ValueError("Value found in more than one instance attribute: " + str(a))
                    found = True
        if found:
            continue
        for k, v in globals().items():
            if a is v:
                retval[k] = v
                if found:
                    raise ValueError("Value found in more than one global variable: " + str(a))
                found = True
        assert found, "Couldn't find one of the parameters."
    return retval

You'll run into problems if you store the same reference in multiple variables, but also if multiple variables store the same small int, since these get interned.

Aleksandr Dubinsky
  • 22,436
  • 15
  • 82
  • 99
-3

why you don't do the opposite :

fruitdict = { 
      'apple':1,
      'banana':'f',
      'carrot':3,
}

locals().update(fruitdict)

Update :

don't use the code above check the comment.

by the way why you don't mark the vars that you want to get i don't know maybe like this:

# All the vars that i want to get are followed by _fruit
apple_fruit = 1
carrot_fruit = 'f'

for var in locals():
    if var.endswith('fruit'):
       you_dict.update({var:locals()[var])
mouad
  • 67,571
  • 18
  • 114
  • 106
  • 5
    Updating `locals()` like that is truly evil. – Greg Hewgill Oct 19 '10 at 21:52
  • As a friend of mine says: 'dark voodoo' – Caleb Hattingh Oct 19 '10 at 21:56
  • agree, but my understanding of his question is that he want to get only variable that are __fruit and legume__ ; which is basically impossible unless he could teach his program to make difference between __fruit and legume__ and other stuff , or maybe i just complicate thing maybe he just want "carrot , banana , apple" vars :) – mouad Oct 19 '10 at 22:11
  • 3
    updating locals() is **forbidden** http://docs.python.org/library/functions.html#locals – John La Rooy Oct 19 '10 at 22:36
-3

Try:

to_dict = lambda **k: k
apple = 1
banana = 'f'
carrot = 3
to_dict(apple=apple, banana=banana, carrot=carrot)
#{'apple': 1, 'banana': 'f', 'carrot': 3}
Lucas
  • 6,869
  • 5
  • 29
  • 44
Prv
  • 3
  • 2
-5
a = "something"
randround = {}
randround['A'] = "%s" % a

Worked.

user1734291
  • 7
  • 1
  • 2
  • 6
  • 1
    It should be `{'a' : 'something'}` and you are getting `{'A' : 'something'}`... you are hard coding the Key `A` – DarkCygnus Jul 19 '17 at 17:35