views:

1896

answers:

6

How can i convert the following:

s = "{'muffin' : 'lolz', 'foo' : 'kitty'}"

Into a dictionary object? I'd prefer not to use eval() what should i do?

The main reason for this, is one of my coworkers classes he wrote, converts all input into strings. I'm not in the mood to go and modify his classes, to deal with this issue.

A: 

I'm sure that he converts all input into strings just so that it's sanitized for eval(). Why wouldn't you use it in this situation? Otherwise you'll just be recoding functionality that already exists.

Kai
+3  A: 

If the string can always be trusted, you could use eval (or use literal_eval as suggested; it's safe no matter what the string is.) Otherwise you need a parser. A JSON parser (such as simplejson) would work if he only ever stores content that fits with the JSON scheme.

Blixt
Starting in 2.6, simplejson is included in the Python standard library as the json module.
Eli Courtwright
Ah, 2.6 seems to be awesome! I've been stuck with 2.5 and have been bad at checking out new features lately... I'll have to read up on all the other new stuff as well I guess =)
Blixt
Yeah, that's a good answer, but note that officially JSON doesn't support single-quoted strings, as given in the original poster's example.
benhoyt
+31  A: 

Starting in Python 2.6 you can use the built-in ast.literal_eval:

>>> import ast
>>> ast.literal_eval("{'muffin' : 'lolz', 'foo' : 'kitty'}")
{'muffin': 'lolz', 'foo': 'kitty'}

This is safer than using eval. As its own docs say:

>>> help(ast.literal_eval)
Help on function literal_eval in module ast:

literal_eval(node_or_string)
    Safely evaluate an expression node or a string containing a Python
    expression.  The string or node provided may only consist of the following
    Python literal structures: strings, numbers, tuples, lists, dicts, booleans,
    and None.

For example:

>>> eval("shutil.rmtree('mongo')")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 1, in <module>
  File "/opt/Python-2.6.1/lib/python2.6/shutil.py", line 208, in rmtree
    onerror(os.listdir, path, sys.exc_info())
  File "/opt/Python-2.6.1/lib/python2.6/shutil.py", line 206, in rmtree
    names = os.listdir(path)
OSError: [Errno 2] No such file or directory: 'mongo'
>>> ast.literal_eval("shutil.rmtree('mongo')")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/opt/Python-2.6.1/lib/python2.6/ast.py", line 68, in literal_eval
    return _convert(node_or_string)
  File "/opt/Python-2.6.1/lib/python2.6/ast.py", line 67, in _convert
    raise ValueError('malformed string')
ValueError: malformed string
Jacob Gabrielson
That's a nice function I didn't know about! +1
Blixt
Thanks, i never knew about that
UberJumper
Why is this a better solution than eval()?
Triptych
@Triptych: good question, clarified...
Jacob Gabrielson
makes me cry that we standardized on python 2.4
David Berger
Interesting. +1/
Triptych
A: 

I can't think of any other way to do this without using eval besides doing some nasty string parsing.

Dan Lorenc
A: 

I'm assuming your coworker is serializing these types with repr(). A purposeful quality of repr() is that, for most simple types, it will produce a string that will create an equivalent object when consumed by eval().

I think by not being willing to use eval(), you're creating an unnecessary amount of work for yourself. If the source of the objectsis trusted, just use it.

Triptych
A: 

If you can't use Python 2.6, you can use a simple safeeval implmenentation like http://code.activestate.com/recipes/364469/

It piggybacks on the Python compiler so you don't have to do all the gross work yourself.

Ned Batchelder