views:

183

answers:

6

given a list of python strings, how can I automatically convert them to their correct type? Meaning, if I have:

["hello", "3", "3.64", "-1"]

I'd like this to be converted to the list

["hello", 3, 3.64, -1]  

where the first element is a stirng, the second an int, the third a float and the fourth an int.

how can I do this? thanks.

+15  A: 
import ast

L = ["hello", "3", "3.64", "-1"]

def tryeval(val):
  try:
    val = ast.literal_eval(val)
  except ValueError:
    pass
  return val

print [tryeval(x) for x in L]
Ignacio Vazquez-Abrams
In honesty, this is a better solution than mine.
jemfinch
but evals are kinda hackish and overpowered
msw
If it's good enough for the Python compiler, then it's good enough for the user.
Ignacio Vazquez-Abrams
you are correct, I was ignorant of the safe semantics of `ast.literal_eval` *bows*
msw
+3  A: 
def tryEval(s):
  try:
    return eval(s, {}, {})
  except:
    return s

map(tryEval, ["hello", "3", "3.64", "-1"])

Only do this if you trust the input. Also, be aware that it supports more than just literals; arithmetic expressions will be evaluated as well.

jemfinch
You should specify exception types (i.e. NameError, SyntaxError).
tgray
In general, yes, but in this implementation, definitely not. Do you really want to attempt the task of determining *all* exceptions that can possibly be raised by `eval`? ZeroDivisionError, TypeError, and probably some more that even I'm not thinking of?
jemfinch
+6  A: 

Without using evaluation:

def convert(val):
    constructors = [int, float, str]
    for c in constructors:
        try:
            return c(val)
        except ValueError:
            pass
Ryan
+1 Avoid using eval add all costs
manifest
+1 pythonically
msw
Great solution (and safe!). The approach can easily be extended to any data type. +1
Arrieta
A: 

If the you are truly interested in only strings, floats, and ints, I prefer the more verbose, less-evalful

def interpret_constant(c):
    try:
        if str(int(c)) == c: return int(c)
    except ValueError:
        pass
    try:
        if str(float(c)) == c: return float(c)
    except ValueError:
        return c

test_list = ["hello", "3", "3.64", "-1"]

typed_list = [interpret_constant(x) for x in test_list]
print typed_list
print [type(x) for x in typed_list]
msw
A: 

This is not really an answer, but I wanted to point out how important this can be when you have a database of parameters with schema ID, PAR, VAL. For instance:

ID  PAR      VAL
001 velocity '123.45'
001 name     'my_name'
001 date     '18-dec-1978'

This schema is appropriate when you don't know how many parameters you need to store for a certain ID. The disadvantage is precisely that the values in VAL are all strings, and need to be converted to the correct data type on demand. You can do this by adding a fourth column to the schema, called TYPE, or you can use any of the approaches proposed thus far.

Good question!

PS. The database schema is related to one of my previous questions.

Arrieta
A: 

A variant of ryans's nice solution, for numpy users:

def tonum( x ):
    """ -> int(x) / float(x) / None / x as is """
    if np.isscalar(x):  # np.int8 np.float32 ...
    # if isinstance( x, (int, long, float) ):
        return x
    try:
        return int( x, 0 )  # 0: "0xhex" too
    except ValueError:
        try:
            return float( x )  # strings nan, inf and -inf too
        except ValueError:
            if x == "None":
                return None
            return x

def numsplit( line, sep=None ):
    """ line -> [nums or strings ...] """
    return map( tonum, line.split( sep ))  # sep None: whitespace
Denis