11

I am trying to take a basic dictionary temp = {'key':array([1,2])} loaded from a .mat file with scipy.io.loadmat. Turn the keys in the Python dictionary file returned by loadmat() into variable names with values the same as the representing keys.

So for example:

temp = {'key':array([1,2])}

turned into

key = array([1,2])

I know how to grab the keys with temp.keys(). Then grabbing the items is easy but how do I force the list of strings in temp.keys() to be variable names instead of strings.

I hope this makes sense but this is probably really easy I just can't think how to do it.

Cheers

Amro
  • 123,847
  • 25
  • 243
  • 454
J Spen
  • 2,614
  • 4
  • 26
  • 41
  • 1
    Why would you want to do that? – Patrick Jun 16 '11 at 09:23
  • I am collaborating with someone that uses Matlab. They send me files that when loaded with loadmat is in a dictionary format. It is easier to work with them temporarily and pass to my functions if I could just write a function to quickly do the above. I agree that it wouldn't matter for a permanent solution but currently it would be rather convenient to mess around with. Since it is usually 5-15 keys it would be rather time consuming to do every time. – J Spen Jun 16 '11 at 10:04
  • 2
    Couldn't you just as easily keep the dictionary and just access the arrays as `temp['key']` without conversion? – JoshAdel Jun 16 '11 at 11:48
  • @JoshAdel: Yes, I could do that but easier in the interactive name space of ipython if I can write a function to do the above. For a permanent solution a dictionary would be no issue. Also I was curious how to do it because I couldn't think of a concise/short way to do it. – J Spen Jun 17 '11 at 03:05

7 Answers7

12

In python, method parameters can be passed as dictionnaries with the ** magic:

def my_func(key=None):
   print key
   #do the real stuff

temp = {'key':array([1,2])}

my_func(**temp)

>>> array([1,2])
Cédric Julien
  • 78,516
  • 15
  • 127
  • 132
4

The best thing to do is to use temp['key']. To answer the question, however, you could use the exec function. The benefits of doing it this way is that you can do this don't have to hard code any variable names or confine yourself to work inside a function.

from numpy import array,matrix

temp = {'key':array([1,2]),'b': 4.3,'c': 'foo','d':matrix([2,2])}

for k in temp:
    exec('{KEY} = {VALUE}'.format(KEY = k, VALUE = repr(temp[k])))

>>> key
array([1, 2])
>>> b
4.3
>>> c
'foo'
>>> d
matrix([[2, 2]])

NOTE : This will only work if you have imported the specific function from the modules. If you don't want to do this because of code practice or the sheer volume of function that you would need to import, you could write a function to concatenate the module name in front of the entry. Output is the same as the previous example.

import numpy as np,numpy

temp = {'key':np.array([1,2]),'b': 4.3,'c': 'foo','d':np.matrix([2,2])}

def exec_str(key,mydict):
    s = str(type(mydict[key]))
    if '.' in s:
        start = s.index("'") + 1
        end = s.index(".") + 1
        v = s[start:end:] + repr(mydict[key])
    else:
        v = repr(mydict[key])     
    return v

for k in temp:
    exec('{KEY} = {VALUE}'.format(KEY = k, VALUE = exec_str(k,temp)))

While this isn't the best code practice, It works well for all of the examples I tested.

Chris Hagmann
  • 1,086
  • 8
  • 14
2

A better way may be to stuff the data to a separate object:

class attrdict(dict):
    def __getattr__(self, k): return self[k]
    def __setattr__(self, k, v): self[k] = v

somedict = {'key': 123, 'stuff': 456}

data = attrdict(somedict)
print data.key
print data.stuff

This is about as easy to use interactively, and does not require any magic. This should be OK for Matlab-users, too.

EDIT: turns out the stuff below doesn't actually work most of the time. Too bad, so much for magic.

If you want to meddle with magic, though, you can do something like

locals().update(somedict)

This will work fine interactively, and you can even hide the access to locals() inside the loader function by messing with sys._getframe().f_back.f_locals.

However, this will not work in functions:

def foo():
    locals().update({'a': 4})
    print a 

The point is that a above is bound to global variable at compile time, and so Python does not try looking it up in among local variables.

pv.
  • 33,875
  • 8
  • 55
  • 49
  • 1
    About the locals() solution : as said in [python documentation](http://docs.python.org/library/functions.html?highlight=locals#locals), `The contents of this dictionary should not be modified` – Cédric Julien Jun 16 '11 at 12:29
  • Ah crap, that's correct -- modifying locals() only works in some cases. – pv. Jun 16 '11 at 13:45
1

To use exec() is more simple as hdhagman answered. I write more simple code.

temp = {'key':[1,2]}

for k, v in temp.items():
    exec("%s = %s" % (k, v))

print(key) => [1,2]

Joonho Park
  • 511
  • 5
  • 17
1

None of the answers above worked for me with numpy arrays and other non-built-in types. However, the following did:

import numpy as np
temp = {'a':np.array([1,2]), 'b': 4.3, 'c': 'foo', 'd':np.matrix([2,2])}
for var in temp.keys():
    exec("{} = temp['{}']".format(var, var))

Note the order of the quotes. This allows var to be treated as a variable in the first instance, and then as a key in the second instance, indexing into the temp dictionary.

Of course, the usual disclaimers about the dangers of exec() and eval() still apply, and you should only run this on input you absolutely trust.

alowet
  • 43
  • 4
0

While I would just recommend using the dictionary directly and accessing the arrays like temp['key'], if you knew all of the variable names ahead of time you could write a function to extract them to individual variables:

def func(**kwargs):
    return kwargs['a'],kwargs['b']


temp = {'a':np.array([1,2]),'b':np.array([3,4])}
a,b = func(**temp)
del temp # get rid of temporary dict
JoshAdel
  • 66,734
  • 27
  • 141
  • 140
0

I had the same question and I tried this code based on the other's answers. Here I used pickle instead of Matlab to store and retrieve the data.

To save data

x1=[2,4,6,8,10]
x2=[1,3,5,7,9]
x3='hello world'
vars={'x1':'x1','x2':'x2','x3':'x3'}

file='test.pickle'
f = open(file,'wb')
for key in vars.keys():
    pickle.dump(eval(vars[key]),f)

del x1,x2,x3

to read from the file

s = open(file,'rb')
for k in vars:
    exec('{KEY} = {VALUE}'.format(KEY = k, VALUE = repr(pickle.load(s))))

print(x1,x2,x3)
Aref
  • 1
  • 1