Как преобразовать строки с рациональными и десятичными числами в числа с плавающей точкой в ​​Python - PullRequest
9 голосов
/ 23 февраля 2009

Как я могу преобразовать строки, которые могут обозначать десятичные или рациональные числа, в числа с плавающей точкой

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

Я бы хотел [0,1234, 0,5].

eval - это то, о чем я думал, но не повезло:

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

Ответы [ 10 ]

16 голосов
/ 23 февраля 2009

Я бы проанализировал строку, если преобразование не удалось:

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

Обычно использование eval - плохая идея, так как это угроза безопасности. Особенно , если оцениваемая строка пришла извне системы.

7 голосов
/ 23 февраля 2009

Как уже отмечали другие, использование eval потенциально представляет угрозу безопасности и, безусловно, является вредной привычкой. (если вы не думаете, что это так же рискованно, как exec, представьте eval что-то вроде: __import__('os').system('rm -rf /'))

Однако, если у вас Python 2.6 или выше, вы можете использовать ast.literal_eval, для которого предусмотрена строка:

может состоять только из следующих Литеральные структуры Python: строки, числа, кортежи, списки, диктанты, логические, и None.

Таким образом, это должно быть вполне безопасно: -)

6 голосов
/ 23 февраля 2009

Другой вариант (также только для версии 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
4 голосов
/ 23 февраля 2009

Используйте from __future__ import division, чтобы получить желаемое поведение. Затем, в крайнем случае, вы можете сделать что-то вроде

from __future__ import division
strings = ["0.1234", "1/2", "2/3"]
numbers = map(eval, strings)

, чтобы получить список значений из ваших строк. Если вы хотите сделать это «правильным» способом, не используйте eval(), а вместо этого напишите функцию, которая принимает строку и вызывает float(), если она не содержит косой черты, или анализирует строку и делит числитель и знаменатель, если в нем есть косая черта.

Один из способов сделать это:

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

Тогда просто map(parse_float_string, strings) получит ваш список.

3 голосов
/ 23 февраля 2009

Оператор / выполняет целочисленное деление. Попробуйте:

>>> 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
2 голосов
/ 23 февраля 2009

Проблема с eval заключается в том, что, как и в python, частное от целых чисел является целым числом. Итак, у вас есть несколько вариантов.

Во-первых, просто сделать возврат целочисленным делением с плавающей запятой:

from __future__ import division

Другой - разделить рациональное число:

reduce(lambda x, y: x*y, map(int, rat_str.split("/")), 1)

Где rat_str - строка с рациональным числом.

1 голос
/ 23 февраля 2009

sympy может помочь вам здесь:

import sympy

half = sympy.Rational('1/2')
p1234 = sympy.Rational('0.1234')
print '%f, %f" % (half, p1234)
1 голос
/ 23 февраля 2009

В Python 3 это должно работать.

>>> x = ["0.1234", "1/2"]
>>> [eval(i) for i in x]
[0.1234, 0.5]
0 голосов
/ 23 февраля 2009

Предложения с from __future__ import division в сочетании с eval, безусловно, будут работать.

Вероятно, стоит указать, что предложения, которые не используют eval, а скорее разбирают строку, делают это потому, что eval опасно: если есть какой-то способ для произвольной строки быть отправленной на eval, тогда ваша система уязвима. Так что это плохая привычка. (Но если это просто быстрый и грязный код, вероятно, это не , что большое дело!)

0 голосов
/ 23 февраля 2009

Это потому, что 1 и 2 интерпретируются Python как целые числа, а не как числа с плавающей точкой. Это должно быть 1.0 / 2.0 или что-то вроде этого.

...