tipos - ¿Cómo convertir cadenas de números racionales y decimales a flotantes en python?
variable tipo texto en python (10)
Analizaría la cadena si la conversión falla:
>>> def convert(s):
try:
return float(s)
except ValueError:
num, denom = s.split(''/'')
return float(num) / float(denom)
...
>>> convert("0.1234")
0.1234
>>> convert("1/2")
0.5
En general, usar eval es una mala idea, ya que es un riesgo para la seguridad. Especialmente si la cadena que se evalúa proviene de fuera del sistema.
¿Cómo puedo convertir cadenas que denotan números decimales o racionales en flotadores?
>>> ["0.1234", "1/2"]
[''0.1234'', ''1/2'']
Me gustaría [0.1234, 0.5].
eval es lo que estaba pensando pero sin suerte:
>>> eval("1/2")
0
Como han señalado otros, el uso de eval
es potencialmente un riesgo para la seguridad y, sin duda, un mal hábito de penetración. (Si no cree que sea tan arriesgado como el exec
, imagine __import__(''os'').system(''rm -rf /'')
algo como: __import__(''os'').system(''rm -rf /'')
)
Sin embargo, si tiene Python 2.6 o superior, puede usar ast.literal_eval
, para lo cual la cadena proporcionada:
solo puede consistir en las siguientes estructuras literales de Python: cadenas, números, tuplas, listas, dictados, booleanos y Ninguno.
Por lo tanto, debería ser bastante seguro :-)
El operador /
hace una división entera. Tratar:
>>> eval("1.0*" + "1/2")
0.5
Como eval()
es potencialmente peligroso, siempre debes verificar con precisión lo que le estás pasando:
>>> import re
>>> s = "1/2"
>>> if re.match(r"/d+//d+$", s):
... eval("1.0*" + s)
...
0.5
Sin embargo, si se toma la molestia de hacer coincidir la entrada con una expresión regular en primer lugar, también podría usar r"(/d+)/(/d+)$"
para extraer el numerador y el denominador, haga la división usted mismo, y evite por completo eval()
:
>>> m = re.match(r"(/d+)/(/d+)$", s)
>>> if m:
... float(m.group(1)) / float(m.group(2))
...
0.5
El problema con eval es que, como en python, el cociente de enteros es un entero. Entonces, tienes varias opciones.
El primero es simplemente hacer flotantes de retorno de división de enteros:
from __future__ import division
El otro es dividir el número racional:
reduce(lambda x, y: x*y, map(int, rat_str.split("/")), 1)
Donde rat_str es la cadena con un número racional.
Esto se debe a que Python interpreta 1 y 2 como enteros y no como flotantes. Necesita ser 1.0 / 2.0 o alguna combinación de eso.
Las sugerencias con la from __future__ import division
combinada con eval
ciertamente funcionarán.
Probablemente valga la pena señalar que las sugerencias que no usan eval
sino que analizan la cadena lo hacen porque eval
es peligroso: si hay alguna forma de enviar una cadena arbitraria a eval
, entonces su sistema es vulnerable. Entonces es un mal hábito. (Pero si esto es solo un código rápido y sucio, ¡probablemente no sea tan importante!)
Otra opción (también solo para 2.6 y superior) es el módulo de fractions
.
>>> from fractions import Fraction
>>> Fraction("0.1234")
Fraction(617, 5000)
>>> Fraction("1/2")
Fraction(1, 2)
>>> float(Fraction("0.1234"))
0.1234
>>> float(Fraction("1/2"))
0.5
Use from __future__ import division
para obtener el comportamiento que desea. Luego, en un apuro, puedes hacer algo como
from __future__ import division
strings = ["0.1234", "1/2", "2/3"]
numbers = map(eval, strings)
para obtener una lista de flotadores de sus cadenas. Si quiere hacer esto de la manera "correcta", no use eval()
, sino que escriba una función que acepte una cadena y llame a float()
si no contiene ninguna barra, o analiza la cadena y divide el numerador y denominador si hay una barra en él.
Una forma de hacerlo:
def parse_float_string(x)
parts = x.split(''/'', 1)
if len(parts) == 1:
return float(x)
elif len(parts) == 2:
return float(parts[0])/float(parts[1])
else:
raise ValueError
Entonces solo el map(parse_float_string, strings)
te dará tu lista.
En Python 3, esto debería funcionar.
>>> x = ["0.1234", "1/2"]
>>> [eval(i) for i in x]
[0.1234, 0.5]
sympy puede ayudarte aquí:
import sympy
half = sympy.Rational(''1/2'')
p1234 = sympy.Rational(''0.1234'')
print ''%f, %f" % (half, p1234)