2010-05-18 14 views
10

dada una lista de cadenas de python, ¿cómo puedo convertirlas automáticamente a su tipo correcto? Es decir, si tengo:convirtiendo python lista de cadenas en su tipo

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

me gustaría que esto se convierte en la lista

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

donde el primer elemento es una stirng, el segundo un int, el tercero un flotador y el cuarto an int.

¿cómo puedo hacer esto? Gracias.

Respuesta

20
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] 
+4

En honestidad, esta es una mejor solución que la mía. – jemfinch

+0

pero las evaluaciones son un poco hackish y dominadas – msw

+1

Si es lo suficientemente bueno para el compilador de Python, entonces es lo suficientemente bueno para el usuario. –

3
def tryEval(s): 
    try: 
    return eval(s, {}, {}) 
    except: 
    return s 

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

Sólo haga esto si confía en la entrada. Además, tenga en cuenta que admite más que solo literales; las expresiones aritméticas serán evaluadas también.

+0

Debe especificar tipos de excepción (es decir, NameError, SyntaxError). – tgray

+0

En general, sí, pero en esta implementación, definitivamente no. ¿Realmente desea intentar la tarea de determinar * todas * las excepciones que posiblemente se puedan generar con 'eval'? ZeroDivisionError, TypeError, y probablemente algunos más que ni siquiera yo estoy pensando en? – jemfinch

8

Sin el uso de la evaluación:

def convert(val): 
    constructors = [int, float, str] 
    for c in constructors: 
     try: 
      return c(val) 
     except ValueError: 
      pass 
+2

+1 Evitar el uso de eval agregar todos los costos – manifest

+1

+1 pythonically – msw

+1

Gran solución (¡y segura!). El enfoque puede extenderse fácilmente a cualquier tipo de datos. +1 – Escualo

0

Si el que está realmente interesado en sólo cadenas, flotadores, y enteros, prefiero el más detallado y menos 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] 
0

Esto no es realmente una respuesta, pero quería señalar lo importante que puede ser esto si tiene una base de datos de parámetros con el esquema ID, PAR, VAL. Por ejemplo:

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

Este esquema es apropiado cuando usted no sabe cuántos parámetros necesita almacenar durante un cierto ID. La desventaja es precisamente que los valores en VAL son todas las cadenas y deben convertirse al tipo de datos correcto según demanda. Puede hacer esto agregando una cuarta columna al esquema, llamada TYPE, o puede usar cualquiera de los enfoques propuestos hasta el momento.

¡Buena pregunta!

PS. El esquema de la base de datos está relacionado con one of my previous questions.

0

Una variante de solución agradable de ryans, para los usuarios numpy:

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 
1

I logra el mismo usando json.loads método

def f(l): 
    for i in l: 
     try: 
      yield json.loads(i) 
     except: 
      yield i 

prueba:

In [40]: l 
Out[40]: ['hello', '3', '3.64', '-1'] 

In [41]: list(f(l)) 
Out[41]: ['hello', 3, 3.64, -1] 
Cuestiones relacionadas