Преобразование из float в Decimal в python-2.6: как это сделать и почему они этого не сделали

Прямое преобразование из float в Decimal было реализовано в python-2.7, как в конструкторе Decimal, так и в методе класса Decimal.from_float().

Python-2.6 вместо этого вызывает TypeError, предлагающий сначала преобразовать в строку:

TypeError: Cannot convert float to Decimal.  First convert the float to a string

так что это обычное обходное решение:

if sys.version_info < (2, 7):
    Decimal.from_float = classmethod(lambda cls, x: cls(str(x)))

Это просто литературный перевод из сообщения об ошибке - и я просто не беспокоюсь о его реализации в конструкторе тоже.

Если это так просто, почему они не внедряли его в первую очередь, а не говорили пользователю сделать это в TypeError? Это лучший доступный метод (и по расширению - тот, который используется в python-2.7 и новее?)

Ответы

Ответ 1

Ваше обходное решение - это не RightWayToDoIt (tm), потому что оно теряет информацию. Способ преобразования без потерь показан в рецепте float_to_decimal(), показанном в Десятичные часто задаваемые вопросы.

Причина, по которой мы не включили Decimal.from_float в Python 2.6, состоит в том, что мы были консервативны в отношении введения непреднамеренных взаимодействий между двоичными поплавками и десятичными поплавками. По Python 2.7 все это было разработано, и вы можете просто написать Decimal(f), где f - двоичный float.

Помимо небольшой неприятности в версии 2.6, я надеюсь, что вам понравится модуль Decimal

Ответ 2

Вероятно, потому что поведение прямого преобразования может быть несовместимым, если вы не знаете несколько сведений о деталях о поплавках. Как указано в документах:

Примечание Decimal.from_float(0.1) не совпадает с Decimal('0.1'). Поскольку 0.1 не является точно представимым в двоичной плавающей точке, значение сохраняется как ближайшее представимое значение, которое равно 0x1.999999999999ap-4. Это эквивалентное значение в десятичном значении 0.1000000000000000055511151231257827021181583404541015625.

Если вы конвертируете в строку, вы можете контролировать точность, которую хотите использовать, чтобы получить точное преобразование в Decimal.

Новый метод был введен в Python 2.7 - поэтому его нет в версии 2.6. Новые функции не поддерживаются более старыми версиями.

Ответ 3

В соответствии с 2.7 Что нового документация (выделено мной)

Конверсии между числами с плавающей запятой и строками теперь правильно скруглен на большинстве платформ. Эти преобразования происходят во многих разные места: str() по поплавкам и комплексным числам; поплавок и сложные конструкторы; цифровое форматирование; сериализации и десериализации поплавков и сложных чисел с использованием маршала, маринования и модули json; разбор поплавка и воображаемых литералов в коде Python; и Преобразование десятичных чисел в плавающие.

Итак, хотя они могли сделать это до 2.7, они, по-видимому, не чувствовали себя комфортно, делая это с проблемами округления, которые существовали.