2010-02-14 11 views
44

Ho dovuto scrivere la seguente funzione per fallire con garbo quando si tenta di analizzare una stringa in un numero intero. Immagino che Python abbia qualcosa di costruito per farlo, ma non riesco a trovarlo. In caso contrario, esiste un modo più pitonico per fare ciò che non richiede una funzione separata?C'è un modo built-in o più Pythonic per provare ad analizzare una stringa su un intero

def try_parse_int(s, base=10, val=None): 
    try: 
    return int(s, base) 
    except ValueError: 
    return val 

La soluzione che ho utilizzato è stata una modifica della risposta di @ sharjeel. Quanto segue è funzionalmente identico, ma, penso, più leggibile.

def ignore_exception(exception=Exception, default_val=None): 
    """Returns a decorator that ignores an exception raised by the function it 
    decorates. 

    Using it as a decorator: 

    @ignore_exception(ValueError) 
    def my_function(): 
     pass 

    Using it as a function wrapper: 

    int_try_parse = ignore_exception(ValueError)(int) 
    """ 
    def decorator(function): 
    def wrapper(*args, **kwargs): 
     try: 
     return function(*args, **kwargs) 
     except exception: 
     return default_val 
    return wrapper 
    return decorator 
+2

Quello che devi sembra bene. –

+1

@Paul Hildebrandt: non solo bello, ma il più Pythonic. –

+0

Penso che il tuo esempio sia anche prezioso per dimostrare un uso pratico per i decoratori. –

risposta

40

Questo è uno scenario abbastanza regolare in modo ho scritto un decoratore "ignore_exception" che funziona per tutti i tipi di funzioni che gettano eccezioni invece di fallire con garbo:

def ignore_exception(IgnoreException=Exception,DefaultVal=None): 
    """ Decorator for ignoring exception from a function 
    e.g. @ignore_exception(DivideByZero) 
    e.g.2. ignore_exception(DivideByZero)(Divide)(2/0) 
    """ 
    def dec(function): 
     def _dec(*args, **kwargs): 
      try: 
       return function(*args, **kwargs) 
      except IgnoreException: 
       return DefaultVal 
     return _dec 
    return dec 

uso nel tuo caso:

sint = ignore_exception(ValueError)(int) 
print sint("Hello World") # prints none 
print sint("1340") # prints 1340 
+0

È intelligente. Bella risposta. –

+4

Sebbene questo sia intelligente, e possibilmente utile anche se stai per decorare molte funzioni con esso, non risponde alla domanda espressa nella riga dell'oggetto. (La risposta alla riga dell'oggetto è: non c'è un built-in, e il codice originale dell'OP è già il modo più pitonico.) –

+0

Sì, sono d'accordo con John, ma ti ho votato per portare la mannaia. –

1

int() è il modo built-in e pythonic, proprio come si ha lì.

Di solito è più facile e più comune usare direttamente però:

def show_square(user_input): 
    """Example of using int().""" 
    try: 
    num = int(user_input, 10) 
    except ValueError: 
    print "Error" # handle not-an-integer case 
    # or you may just want to raise an exception here 
    # or re-raise the ValueError 
    else: 
    print "Times two is", num * 2 

def another_example(user_input): 
    try: 
    num = int(user_input, 10) 
    except ValueError: 
    num = default 
    print "Times two is", num * 2 
7

No, è già perfetta. Tuttavia, il parametro val potrebbe essere definito come predefinito.

documentato nella documentazione ufficiale semplicemente come int(x) -- x converted to integer

+1

Grazie. È sfortunato che non ci sia un mezzo integrato per analizzare un numero intero che non genera un'eccezione. –

+6

@Christopher: Perché è sfortunato? Come si fa a provare, tranne che non è incorporato? –

+0

@Christopher: Ecco com'è la "cultura" di Python e sono sicuro che troverai lo stesso pattern in altri posti – u0b34a0f6ae

6

vorrei andare per:

def parse_int(s, base=10, val=None): 
if s.isdigit(): 
    return int(s, base) 
else: 
    return val 

Ma è più o meno la stessa cosa.

+1

Non sapeva di str.isdigit. Potrebbe essere utile. Grazie. –

+0

Si prega di prendere in considerazione la risposta abyx. Ha ragione e dovresti usare il tuo codice, invece del mio. – Macarse

+2

Non solo lo stile EAFP è più appropriato e più Pythonic in questa situazione, gestisce gli interi negativi mentre isdigit no. –

21

Questo è il modo pitonico. In Python, è consuetudine usare lo stile EAFP: è più facile chiedere perdono che autorizzazione.
Ciò significa che proverai prima, e poi ripulisci il pasticcio se necessario.

+0

@abyx: Mi piacciono le prime due frasi. Non mi piace il terzo. Quando dici "poi, una volta che sei sicuro di eseguire l'azione", sembra che tu stia descrivendo LBYL, anche se la prima parte di questa frase è più o meno corretta per EAFP. Direi "EAFP = prova e pulisci il casino se fallisce". –

18
def intTryParse(value): 
    try: 
     return int(value), True 
    except ValueError: 
     return value, False 
+1

Soluzione piacevole. Semplice e al punto. –

0
def parseint(string): 
    result = '0' 
    for x in string: 
     if x.isdigit(): 
     result+=x 
    else: 
     return int(result) 
    return int(result) 
+1

Cattiva idea. Produce risultati fasulli. Supponendo che il rientro sulla riga 5 sia corretto, parametrico ('- 3') => 3; parseint ('2by2') => 22; ecc. Si noti inoltre che il primo ritorno viene sempre eseguito poiché non vi è alcuna interruzione nel ciclo. – Vroo

0
myList = ['12', '13', '5', 'hope', 'despair', '69','0', '1.2'] 

myInts = [int(x) for x in myList if x.isdigit()] 
Problemi correlati