2010-05-18 5 views
10

gegeben eine Liste von Python-Strings, wie kann ich sie automatisch in den richtigen Typ konvertieren? Das heißt, wenn ich:Konvertieren von Python-Liste von Zeichenfolgen in ihren Typ

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

ich diese in die Liste umgewandelt werden möchten

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

wobei das erste Element ein stirng ist, der zweite ein int, der dritte ein Schwimmer und die vierte an int.

Wie kann ich das tun? Vielen Dank.

Antwort

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

In Ehrlichkeit, das ist ein bessere Lösung als meine. – jemfinch

+0

aber evals sind irgendwie hackish und überwältigt – msw

+1

Wenn es gut genug für den Python-Compiler ist, dann ist es gut genug für den Benutzer. –

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

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

dies nur tun, wenn Sie die Eingabe vertrauen. Beachten Sie auch, dass es mehr als nur Literale unterstützt. arithmetische Ausdrücke werden ebenfalls ausgewertet.

+0

Sie sollten Ausnahmetypen angeben (z. B. NameError, SyntaxError). – tgray

+0

Im Allgemeinen ja, aber in dieser Implementierung definitiv nicht. Wollen Sie wirklich versuchen, * alle * Ausnahmen zu bestimmen, die möglicherweise von 'eval' ausgelöst werden können? ZeroDivisionError, TypeError und wahrscheinlich noch mehr, an die ich nicht einmal denke? – jemfinch

8

Ohne Bewertung mit:

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

+1 Vermeiden Sie die Verwendung von eval addieren Sie alle Kosten – manifest

+1

+1 pythonisch – msw

+1

Große Lösung (und sicher!). Der Ansatz kann leicht auf jeden Datentyp erweitert werden. +1 – Escualo

0

Wenn das sind Sie wirklich daran interessiert, nur Strings, Schwimmern, und ints, ziehe ich die ausführlichere, weniger 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

Dies ist nicht wirklich eine Antwort, aber ich wollte darauf hinweisen, wie wichtig dies sein kann, wenn Sie eine Datenbank mit Parametern mit dem Schema ID, PAR, VAL haben. Zum Beispiel:

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

Dieses Schema ist geeignet, wenn Sie nicht wissen, wie viele Parameter, die Sie für ein bestimmtes ID speichern müssen. Der Nachteil ist genau, dass die Werte in VAL alle Zeichenfolgen sind und bei Bedarf in den richtigen Datentyp konvertiert werden müssen. Sie können dies tun, indem Sie dem Schema eine vierte Spalte mit dem Namen TYPE hinzufügen, oder Sie können einen der bisher vorgeschlagenen Ansätze verwenden.

Gute Frage!

PS. Das Datenbankschema bezieht sich auf one of my previous questions.

0

Eine Variante des ryans der schöne Lösung, für numpy Benutzer:

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

ich das gleiche mit json.loads Verfahren erreicht

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

Test:

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

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