2011-04-09 12 views
9

No pude encontrar otra respuesta cuando quería esto, así que pensé en publicar mi propia solución para cualquier otra persona y también obtener correcciones si he hecho algo mal.¿Cómo puedo convertir una cadena en int o float con prioridad en int?

Tenía que hacer un analizador automático de archivos de configuración y preferí hacer números int si fuera posible y flotar si no. La conversión try/except habitual no funciona por sí sola ya que cualquier float solo se forzará a un int.

Para aclarar como alguien preguntó, el caso es básicamente para convertir números como la persona que escribe los datos del archivo de configuración pretendía que fueran. Entonces, cualquier cosa con decimales probablemente sea una flotación. Además, creo que la flotación puede ser peligrosa para algunos operadores (por ejemplo, ==, <,>) debido a la naturaleza de los números de punto flotante, y int se convertirá en flotación cuando sea necesario. Por lo tanto, prefiero que los números permanezcan en int cuando sea posible. No es una gran cosa, solo como una especie de convención para mí.

+1

posible duplicado de [Python - Parse String to Float o Int] (http://stackoverflow.com/questions/379906/python-parse-string-to-float-or-int) – Johnsyweb

+0

NO es un duplicado; esa pregunta pide algo diferente. –

+1

Edite su pregunta para dar ejemplos que aclaren lo que quiere decir con "hacer números int si es posible". En particular, ¿quiere que "10.0000" (donde la intención del usuario es obviamente flotante) se convierta en 'int' o' float'. –

Respuesta

21
def int_or_float(s): 
    try: 
     return int(s) 
    except ValueError: 
     return float(s) 

Si quieres algo así como "10.0000" convierte a int, intente esto:

def int_dammit_else_float(s): 
    f = float(s) 
    i = int(f) 
    return i if i == f else f 

¿Qué resultado que desea para la entrada como "1e25"?

+0

Guau, me sentí tonto cuando me di cuenta de que su primera solución hace exactamente lo que yo quería. Estaba trabajando bajo la comprensión errónea de que int ('1.1') forzaría a 1 dado que int (1.1) sí lo hace. Gracias por la respuesta y ayudándome a corregir mi suposición equivocada. – KobeJohn

2

Este es un momento en el que probablemente sea mejor obtener permiso antes que pedir perdón más tarde, que generalmente se considera la forma "pitónica" de hacer las cosas y generalmente implica try/except. Así que algo tan simple como esto podría ser lo suficientemente bueno:

v = float(s) if '.' in s or 'e' in s.lower() else int(s) 

Dado que hay más de un personaje que puede indicar un número de coma flotante, que podría también comprobar si hay uno de ellos estas siguientes maneras:

import re 
pattern = re.compile(r'[.eE]') 
v = float(s) if pattern.findall(s) else int(s) 

o

chars = set('.eE') 
v = float(s) if any((c in chars) for c in s) else int(s) 

por último, en una pista ligeramente diferente, si desea flotante números enteros de punto de convertirse en números enteros, se puede hacer lo siguiente, que es similar a @ John M La función del achin "_dammit_":

v = int(float(s)) if int(float(s)) == float(s) else float(s) 
+0

Solo si sabes todo lo que deberías estar preguntando; intente "1E-6" –

+0

@John Machin: Buen punto en general, pero aquí probablemente aún sea manejable (vea mi actualización). – martineau

+0

Gracias por el código martineau. Funcionará muy bien para mis necesidades y simplificará lo que tenía. De hecho, omitiré la notación E porque una vez que comience a manejar los casos, creo que sería mejor usar una expresión regular para detectar todos los casos. – KobeJohn

2

eval (s)

eval() es una función que acepta una cadena y lo procesa como código Python. Cuando se le dé cualquier tipo de literal como cadena, devolverá un objeto Python que contenga ese valor.

Sin embargo, desde el punto de vista de la seguridad, esta es una mala idea, ya que alguien podría potencialmente dar instrucciones que bloqueen o alteren su programa. Se podría exigir la forma de un determinado conjunto de caracteres antes del procesamiento, es decir .:

eval(s) if not set(s).difference('.') else None 

Esto todavía probablemente no vale la pena el dolor de cabeza, sin embargo. Dicho esto, puede hacerse elegante y permitir expresiones con cálculos también ... ¡y eso podría valer la pena intentarlo!

num = lambda s: eval(s) if not set(s).difference('. *+-/e') else None 

>>> num('10') 
10 
>>> num('10.0') 
10.0 
>>> num('1e3') 
1000.0 
>>> num('4.8 * 10**34') 
4.8e+34 
>>> num('1+2/3') 
1.6666666666666665 
2
def int_float_none(x): 
    # it may be already int or float 
    if isinstance(x, (int, float)): 
     return x 
    # all int like strings can be converted to float so int tries first 
    try: 
     return int(x) 
    except (TypeError, ValueError): 
     pass 
    try: 
     return float(x) 
    except (TypeError, ValueError): 
     return None 

función anterior para cualquier objeto pasado volverá int o flotar conversión o Ninguno.