How can I convert strings which can denote decimal or rational numbers to floats
>>> ["0.1234", "1/2"]
['0.1234', '1/2']
I'd want [0.1234, 0.5].
eval is what I was thinking but no luck:
>>> eval("1/2")
0
How can I convert strings which can denote decimal or rational numbers to floats
>>> ["0.1234", "1/2"]
['0.1234', '1/2']
I'd want [0.1234, 0.5].
eval is what I was thinking but no luck:
>>> eval("1/2")
0
The /
operator does integer division. Try:
>>> eval("1.0*" + "1/2")
0.5
Because eval()
is potentially dangerous, you should always check precisely what you are passing into it:
>>> import re
>>> s = "1/2"
>>> if re.match(r"\d+/\d+$", s):
... eval("1.0*" + s)
...
0.5
However, if you go to the trouble of matching the input against a regex in the first place, you might as well use r"(\d+)/(\d+)$"
to extract the numerator and denominator, do the division yourself, and entirely avoid eval()
:
>>> m = re.match(r"(\d+)/(\d+)$", s)
>>> if m:
... float(m.group(1)) / float(m.group(2))
...
0.5
That's because 1 and 2 are interpreted by Python as integers and not floats. It needs to be 1.0/2.0 or some mix of that.
Use from __future__ import division
to get the behavior you want. Then, in a pinch, you can do something like
from __future__ import division
strings = ["0.1234", "1/2", "2/3"]
numbers = map(eval, strings)
to get a list of floats out of your strings. If you want to do this the "right" way, don't use eval()
, but instead write a function that accepts a string and calls float()
on it if it contains no slash, or parses the string and divides the numerator and denominator if there's a slash in it.
One way to do it:
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
Then just map(parse_float_string, strings)
will get you your list.
The problem with eval is that, as in python, the quotient of integers is an integer. So, you have several choices.
The first is simply to make integer division return floats:
from __future__ import division
The other is to split the rational number:
reduce(lambda x, y: x*y, map(int, rat_str.split("/")), 1)
Where rat_str is the string with a rational number.
I'd parse the string if conversion fails:
>>> 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
Generally using eval is a bad idea, since it's a security risk. Especially if the string being evaluated came from outside the system.
The suggestions with from __future__ import division
combined with eval
will certainly work.
It's probably worth pointing out that the suggestions that don't use eval
but rather parse the string do so because eval
is dangerous: if there is some way for an arbitrary string to get sent to eval
, then your system is vulnerable. So it's a bad habit. (But if this is just quick and dirty code, it's probably not that big a deal!)
As others have pointed out, using eval
is potentially a security risk, and certainly a bad habit to get into.
(if you don't think it's as risky as exec
, imagine eval
ing something like: __import__('os').system('rm -rf /')
)
However, if you have python 2.6 or up, you can use ast.literal_eval
, for which the string provided:
may only consist of the following Python literal structures: strings, numbers, tuples, lists, dicts, booleans, and None.
Thus it should be quite safe :-)
Another option (also only for 2.6 and up) is the fractions
module.
>>> 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
In Python 3, this should work.
>>> x = ["0.1234", "1/2"]
>>> [eval(i) for i in x]
[0.1234, 0.5]
sympy can help you out here:
import sympy
half = sympy.Rational('1/2')
p1234 = sympy.Rational('0.1234')
print '%f, %f" % (half, p1234)