2010-02-14 12 views
44

Tuve que escribir la siguiente función para que fallara graciosamente al intentar analizar una cadena en un entero. Me imagino que Python tiene algo incorporado para hacer esto, pero no puedo encontrarlo. Si no, ¿hay una forma más Pythonic de hacer esto que no requiere una función separada?¿Hay una forma incorporada o más de Pythonic para intentar analizar una cadena a un número entero

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

La solución que terminé usando fue una modificación de la respuesta de @ sharjeel. Lo siguiente es funcionalmente idéntico, pero, creo, más legible.

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

Lo que tienes parece bien –

+1

@Paul Hildebrandt: No solo es bueno, sino también lo más pitónico. –

+0

Creo que su ejemplo también es valioso para demostrar un uso práctico para los decoradores. –

Respuesta

40

Este es un escenario bastante regular por lo que he escrito un decorador "ignore_exception" que funciona para todo tipo de funciones que generen excepciones en lugar de fallar con gracia:

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 en su caso:

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

Eso es inteligente. Gran respuesta. –

+4

Si bien esto es inteligente, y posiblemente incluso útil si va a decorar muchas funciones con él, no responde a la pregunta tal como se expresa en la línea de asunto. (La respuesta a la línea de asunto es: no hay incorporado, y el código original de OP es ya la forma más pitonica.) –

+0

Sí, estoy de acuerdo con John, pero te voté por traer el cuchillo. –

1

int() es la manera incorporada y pitonica, como la que tiene allí.

Por lo general es más fácil y más común utilizar directamente sin embargo:

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, ya es perfecto. Sin embargo, el parámetro val podría nombrarse mejor por defecto.

documentado en los documentos oficiales simplemente como int(x) -- x converted to integer

+1

Gracias. Es desafortunado que no haya medios incorporados de analizar un entero que no genere una excepción. –

+6

@Christopher: ¿Por qué es desafortunado? ¿Cómo se prueba, excepto que no está incorporado? –

+0

@Christopher: Así es como es la "cultura" de Python y estoy seguro de que encontrarás el mismo patrón en otros lugares – u0b34a0f6ae

6

Yo iría por:

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

Pero es más o menos lo mismo.

+1

No sabía sobre str.isdigit. Eso podría ser útil. Gracias. –

+0

Por favor, tenga en cuenta la respuesta abyx. Él tiene razón y deberías usar tu código, en lugar del mío. – Macarse

+2

No solo es el estilo de EAFP más apropiado y más Pythonic en esta situación, maneja enteros negativos mientras que isdigit no lo hace. –

21

Esa es la manera pitónica. En python, es costumbre utilizar el estilo EAFP: es más fácil pedir perdón que el permiso.
Eso significa que deberías probar primero y luego limpiar el desorden si es necesario.

+0

@abyx: Me gustan las dos primeras oraciones. No me gusta el tercero. Cuando dice "entonces una vez que está seguro de realizar la acción", parece que está describiendo LBYL, aunque la primera parte de esa oración es más o menos correcta para EAFP. Yo diría "EAFP = solo inténtalo, y limpia el desorden si falla". –

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

Buena solución. Simple y al grano. –

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

Mala idea. Produce resultados falsos. Suponiendo que la sangría en la línea 5 es fija, parseint ('- 3') => 3; parseint ('2by2') => 22; etc. Tenga en cuenta también que la primera devolución siempre se ejecuta ya que no hay interrupción en el ciclo. – Vroo

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

myInts = [int(x) for x in myList if x.isdigit()] 
Cuestiones relacionadas