У меня есть большой код python, который пытается обрабатывать числа с 4-мя десятичной точностью, и я застрял с python 2.4 по многим причинам. Код делает очень упрощенную математику (ее код управления кредитами, который берет или добавляет кредиты в основном)
В нем используется смешанное использование float и Decimal (MySQLdb возвращает десятичные объекты для типов SQL DECIMAL). После нескольких странных ошибок, возникающих из-за использования, я обнаружил, что основной причиной всех было несколько мест в коде, который плавает, и Decimals сравниваются.
Я получил такие случаи:
>>> from decimal import Decimal
>>> max(Decimal('0.06'), 0.6)
Decimal("0.06")
Теперь я боюсь, что не могу уловить все такие случаи в коде. (нормальный программист будет продолжать делать x > 0 вместо x > Decimal ('0.0000'), и его очень трудно избежать)
Я придумал патч (вдохновленный усовершенствованиями десятичного пакета в python 2.7).
import decimal
def _convert_other(other):
"""Convert other to Decimal.
Verifies that it ok to use in an implicit construction.
"""
if isinstance(other, Decimal):
return other
if isinstance(other, (int, long)):
return Decimal(other)
# Our small patch begins
if isinstance(other, float):
return Decimal(str(other))
# Our small patch ends
return NotImplemented
decimal._convert_other = _convert_other
Я просто делаю это в очень ранней загрузочной библиотеке, и он изменит поведение десятичного пакета, разрешив преобразование с плавающей запятой в Decimal перед сравнением (чтобы избежать удара по объекту по умолчанию для объекта python).
Я специально использовал "str" вместо "repr", поскольку он исправляет некоторые случаи округления с плавающей запятой. Например.
>>> Decimal(str(0.6))
Decimal("0.6")
>>> Decimal(repr(0.6))
Decimal("0.59999999999999998")
Теперь мой вопрос: Я что-то пропустил? Это достаточно безопасно? или я что-то сломаю? (Я думаю, что у авторов пакета были очень веские причины, чтобы избежать так много плавать)