10

小数または有理数を表すことができる文字列を浮動小数点数に変換するにはどうすればよいですか

>>> ["0.1234", "1/2"]
['0.1234', '1/2']

[0.1234、0.5]が欲しいです。

eval は私が考えていたものですが、運はありません:

>>> eval("1/2")
0
4

10 に答える 10

19

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.

于 2009-02-22T22:18:47.247 に答える
7

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 evaling 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 :-)

于 2009-02-22T22:34:55.057 に答える
7

別のオプション (これも 2.6 以降のみ) は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
于 2009-02-22T23:04:44.267 に答える
4

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.

于 2009-02-22T22:16:05.367 に答える
3

/演算子は整数除算を行います。試す:

>>> eval("1.0*" + "1/2")
0.5

は潜在的に危険であるためeval()、渡す内容を常に正確に確認する必要があります。

>>> import re
>>> s = "1/2"
>>> if re.match(r"\d+/\d+$", s):
...     eval("1.0*" + s)
...
0.5

ただし、そもそも入力を正規表現と照合するのに苦労する場合はr"(\d+)/(\d+)$"、分子と分母を抽出し、自分で除算を行い、完全に回避するために使用することもできeval()ます。

>>> m = re.match(r"(\d+)/(\d+)$", s)
>>> if m:
...     float(m.group(1)) / float(m.group(2))
...
0.5
于 2009-02-22T22:13:30.990 に答える
2

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.

于 2009-02-22T22:17:37.360 に答える
1

Python 3では、これは機能するはずです。

>>> x = ["0.1234", "1/2"]
>>> [eval(i) for i in x]
[0.1234, 0.5]
于 2009-02-23T00:18:53.903 に答える
1

sympyはここであなたを助けることができます:

import sympy

half = sympy.Rational('1/2')
p1234 = sympy.Rational('0.1234')
print '%f, %f" % (half, p1234)
于 2009-02-23T02:54:20.767 に答える
0

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!)

于 2009-02-22T22:29:11.513 に答える
0

これは、1 と 2 が Python によって浮動小数点数ではなく整数として解釈されるためです。1.0/2.0 またはその混合である必要があります。

于 2009-02-22T22:15:39.750 に答える