12
votes

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?).

1
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
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
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
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

1 Answers

29
votes

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')}