13

I'm making a webapp that does some data processing, so I frequently find myself parsing strings (from an URL or a text file) into Python values.

I use a function that is "kind of" a safer version of eval (except that if it can't read the string, it stays a string):

def str_to_value(string):
    for atom in (True, False, None):
        if str(atom) == string:
            return atom
    else:
        try:
            return int(string)
        except ValueError:
            try:
                return float(string)
            except ValueError:
                return string

... however, this seems very ugly to me. Is there a cleaner way of doing this? I found an old discussion os something like this, but I'm wondering if there isn't a quick and simple way (like a library function I don't know of, or a clever one-liner?).

Community
  • 1
  • 1
Emile
  • 2,946
  • 2
  • 19
  • 22
  • No, I think that if you want to allow any of these types this is probably the way to do it. But it seems strange to me. Don't you know what type the input will be? How will you know what to do with the input? – Lennart Regebro Dec 08 '10 at 14:37
  • 1
    This isn't safe unless you trust `string` to be a `str` (and not a subclass, either) -- otherwise, an evildoer could write a class with a malicious `__eq__` method which would be called when you test whether your string looks like True. – Katriel Dec 08 '10 at 15:08
  • Lennart: for example, I may use this kind of conversion in a generic CsvToDict function, which will then be used in ExpectKeysToBeInts(CsvToDict("ints_as_keys.csv")) and in ExpectValuesToBeFloats(CsvToDict("float_values.csv")) - I'd rather my ExpectKeysToBeInts and ExpectValuesToBeFloats stayed simple and didn't have to care about data conversion. – Emile Dec 08 '10 at 16:02
  • 1
    katrielalex: right, I'm getting all my data as strings (I think that if I'm getting untrusted Python object, there's probably already a huge security hole somewhere else). – Emile Dec 08 '10 at 16:05

1 Answers1

30

ast.literal_eval()

>>> ast.literal_eval('{False: (1, 0x2), True: [3.14, 04, 0b101], None: ("6", u"7", r\'8\')}')
{False: (1, 2), True: [3.1400000000000001, 4, 5], None: ('6', u'7', '8')}
Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • 1
    Thanks! [Guido's Time Machine](http://dirtsimple.org/2004/12/python-is-not-java.html) strikes again! I'll have to dig through the ast library, it's one of those "general purpose" libraries that's most likely to contain useful stuff (like itertools, functools, collections ...) – Emile Dec 08 '10 at 16:42
  • 4
    I just realized how many evil dirty hacks I've created in the past that should have been using this instead of plain `eval`. Ouch. :) – Karl Knechtel Dec 08 '10 at 16:46