У меня есть большое количество кода на Python, который пытается обрабатывать числа с 4-мя десятичной точностью, и я застрял с python 2.4 по многим причинам. Код делает очень упрощенную математику (ее код управления кредитами, который принимает или добавляет кредиты в основном)Зло в python decimal/float
Он имеет смешанное использование 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's 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
Я просто сделать это в самом начале загрузки библиотеки и изменит десятичное поведение пакета, позволяя плавать в десятичное преобразование до сравнения (чтобы избежать удара объекта питона по умолчанию для объекта сравнения).
Я специально использовал «str» вместо «repr», так как он исправляет некоторые закругляющие случаи флота. Например.
>>> Decimal(str(0.6))
Decimal("0.6")
>>> Decimal(repr(0.6))
Decimal("0.59999999999999998")
Теперь мой вопрос: Я пропускаю здесь что-нибудь? Это достаточно безопасно? или я что-то сломаю? (Я думаю, что у авторов пакета были очень веские причины, чтобы избежать поплавков)
Просто обратите внимание, что «return NotImplemented» - это сам пакет decimal.py. Две строки, которые я добавил, находятся между комментариями. Однако я согласен с вашим подходом в этой реализации, python позволяет логически сумасшедшие сравнения между объектами, которые мы предполагаем, являются обоими числами. Хм, другая идея может заключаться в том, чтобы поднять ошибку вместо неявного преобразования, но независимо от того, я думаю, что мне нужно что-то сделать ... –
'return NotImplemented' является правильным и является правильным, [указанная документация] (http: // docs .python.org/reference/datamodel.html # emulating-numeric-types), чтобы вернуться для неподдерживаемого сравнения. Это позволяет питону пытаться найти другой способ сделать что-то. – aaronasterling
+1 для использования термина «патч обезьяны», который привел меня к википедии этого термина, чтобы найти его из «партизанских патчей», как в партизанской войне =). – Tommy