19

I tried to ask this question once before, but nobody understood what I want to ask. So I've found example in PHP.

// $_POST = array('address' => '123', 'name' => 'John Doe');
extract($_POST);
echo $address;
echo $name

Is there's a function like extract() in Python?

So the same goes to dictionary:

mydict = {'raw':'data', 'code': 500}
// some magic to extract raw and code as vars
print raw

P.S. Why I want to do this: When you're in class method, it's damned hard to have 6 manipulation with strings in join() and format() when string is self.data['raw']['code'] (assume it's a dict in a dict).

martineau
  • 119,623
  • 25
  • 170
  • 301
holms
  • 9,112
  • 14
  • 65
  • 95
  • 5
    The question as expressed in the title is very misleading. "Convert dictionary to string" sounds like you want to serialize the dictionary (with pickle or json, for example) or pretty-print it (pprint). "Creating or assigning variables from a dictionary" might be closer to the intended question. – John Y Dec 05 '10 at 08:39

7 Answers7

26

You can use the locals() function to access the local symbol table and update that table:

>>> mydict = {'raw': 'data', 'code': 500}
>>> locals().update(mydict)
>>> raw
'data'
>>> code
500

Modifying the symbol table that way is quite unusual, though, and probably not the way to go. Maybe you need to change your design so you can use the mydict dictionary instead of actual variables.

Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
  • i would like "to change design" in one line of code only for this method, by extracting that damned dictionary, I was doing in php this way all the time.. – holms Dec 05 '10 at 07:50
  • 1
    +1 for an unusual, non-idiomatic thing you can do with Python, but probably shouldn't. – Zeke Dec 05 '10 at 07:52
  • @holms, maybe you could cache `self.data['raw']` into, say, a variable `d` and use that variable instead? It would be shorter: `d['code']` instead of `self.data['raw']['code']`. – Frédéric Hamidi Dec 05 '10 at 07:53
  • Just because you *can* doesn't mean you *should*! – johnsyweb Dec 05 '10 at 08:12
  • @holms - If you were using `extract` 'all the time' in PHP then that means that you are a crappy PHP coder. `extract` is a lazy and terrible way to do things (with the exception of templates) because it surrenders control of the local scope to a passed in argument. HTH :) – aaronasterling Dec 05 '10 at 20:12
  • 5
    It's also worth noting that doing it this way will make it so that the `CO_OPTIMIZED` flag isn't set on the resulting code object (read about it in 'code.h'). This means that the compiler won't use the `*_FAST` instructions in the code and will have to use the corresponding `*_NAME` instructions. So the code will also run slower. – aaronasterling Dec 05 '10 at 20:25
  • 1
    -1: because, as @John Y points out in his answer, the documentation for `locals()` specifically notes that the contents of the dictionary returned should not be modified. – martineau Dec 06 '10 at 15:58
  • 1
    It should be noted that it does not work outside of global scope https://stackoverflow.com/questions/37600997/python-locals-update-not-working and it is a bad idea https://stackoverflow.com/questions/4997184/why-is-it-bad-idea-to-modify-locals-in-python – Diblo Dk May 13 '20 at 17:27
10

Horribly late to the game, but I needed exactly this, and my solution was:

mydict = {'raw':'data', 'code': 500}
raw, code = [mydict.get(k) for k in ['raw','code']]

That way it's explicit for reading and there's no potential clobbering of locals() (which is a magic that I'd rather avoid).

cybertoast
  • 1,343
  • 13
  • 19
  • 7
    But this is not dynamic, i.e., the name of the variables cannot be assigned dynamically on runtime, or their number change. – 0 _ Aug 02 '13 at 18:25
  • Works even better with second line like this: `raw, code = [mydict.get(k) for k in mydict]` – BartBiczBoży Jan 05 '17 at 07:28
4

OK php brothers so here is a bad news, python can't create variables from out of space... like php can: ${$var} . To use local() is a very bad idea, because you'll have tons of problems with debugging, and there some locals already defined in there.. so it's really bad thing to do...

You can't create this programmatically like php does. I think it's called non-explicity, and this is one python general: You ALWAYS know variable name. This kind of stuff just a suicide in some cases, you need to write by hand tons of vars... Mostly i was unhappy because of things like XML parsing, but it appears that there are method how to convert python dictionary into class, I was told about this yesterday but still haven't checked how it works ( something like here )

Community
  • 1
  • 1
holms
  • 9,112
  • 14
  • 65
  • 95
  • 1
    The more implicit the existence of variables in you current namespace becomes, the more problems the code will have and cannot scale. This is a major argument against globals. The same applies to this case. You wouldn't want to have many variable implicitly created, this approach is a last resort, which at the minimum hampers readability, cf [Zen of Python](http://www.python.org/dev/peps/pep-0020/). – 0 _ Aug 02 '13 at 18:30
  • and now I 100% agree with you. Migrated from php long time ago - and I'm insanely happy about this. – holms Aug 19 '14 at 04:00
3

Nothing really new here, just a consolidation of one answer and an illustration of what @John Y meant in his answer:

mydict = {'raw': 'data', 'code': 500}

def extract(dct, namespace=None):
    if not namespace: namespace = globals()
    namespace.update(dct)

extract(mydict)
print(raw)
print(code)

class Extract:
    def __init__(self, dct):
        self.__dict__.update(dct)

obj = Extract(mydict)
print(obj.raw)
print(obj.code)
martineau
  • 119,623
  • 25
  • 170
  • 301
  • Good answer, but as a reminder remember to use class – Diblo Dk May 13 '20 at 17:41
  • @DibloDk: I rolled-back your code change — it's unnecessary (see the ActiveState [recipe](https://code.activestate.com/recipes/52308-the-simple-but-handy-collector-of-a-bunch-of-named/)). – martineau May 13 '20 at 17:51
2

I recommend creating a class to hold the variables you're trying to create. Alex Martelli's famous bunch recipe would get you almost all of the convenience you are asking for, without resorting to modifying the local symbol table (which the docs specifically warn against doing).

John Y
  • 14,123
  • 2
  • 48
  • 72
1

I tried @Frédéric Hamidi's answer and found that locals() only works in the main script and does NOT work in any functions. So I did a bit of searching, and find out that locals() is READ ONLY. The reason it works in main script, is probably cause locals() is the same as globals() there, and globals() can be modified.

So I would suggest using globals().update() instead.

But it is going to pollute your global namespace. So this trick is even less clean than locals().

liren
  • 21
  • 2
  • This may be appropriate as a comment, but it doesn't really answer the question. Please wait until you have the rep to comment instead. – skrrgwasme Aug 18 '14 at 23:10
  • @ScottLawson The locals() answer is WRONG, cause it only works in the first level of indentation, cause that's where locals() is the same as globals(). If one needs a dirty way as locals().update(), it should be globals() not locals(). That's all I was saying. globals().update() IS an answer to the original question, and it is a correct one. – liren Sep 12 '14 at 15:31
  • I see your point. My downvote is locked unless your answer is edited. Give it a quick edit and I'll remove it. – skrrgwasme Sep 12 '14 at 15:43
0

You can also use the exec keyword in a loop.

d = dict(param='hello', param2=500, param3=[1,2,3])
for k, v in d.iteritems():
    exec '%s = v' % k

But this certainly feels unpythonic. exec feels a bit esoteric and you should probably just restructure your code so you don't have to do this.

Jake Biesinger
  • 5,538
  • 2
  • 23
  • 25