десятичное сравнение python
питон десятичных сравнение
>>> from decimal import Decimal
>>> Decimal('1.0') > 2.0
True
Я ожидал, что он правильно преобразует 2.0, но после чтения через PEP 327 Я понимаю, что была какая-то причина для неявного преобразования float в Decimal, но в этом случае он не должен поднимать TypeError, как это происходит в этом случае
>>> Decimal('1.0') + 2.0
Traceback (most recent call last):
File "<string>", line 1, in <string>
TypeError: unsupported operand type(s) for +: 'Decimal' and 'float'
так же, как и все другие операторы / - % / / etc
Итак, мои вопросы
- это правильное поведение? (не вызывать исключения в ЦМП)
- что делать, если я получаю свой собственный класс и правый поплавковый преобразователь в основном Decimal (repr (float_value)), являются есть какие-то оговорки? моем случае использовать включает только сравнение цен
сведения о системе: Python 2.5.2 на Ubuntu 8.04.1
3 ответов
Re 1, это действительно поведение, которое мы разработали-правильно или неправильно, как это может быть (извините, если это отключает ваш вариант использования, но мы пытались быть общими!).
в частности, уже давно было так, что каждый объект Python может подвергаться неравенству сравнения со всеми другими-объекты типов, которые на самом деле не сопоставимы, получают произвольное сравнение (последовательно в данном прогоне, не обязательно через прогоны); основным вариантом использования была сортировка гетерогенного списка в группу элементы по типу.
исключение было введено только для комплексных чисел, что делает их несопоставимыми ни с чем-но это было еще много лет назад, когда мы иногда были бесцеремонны о взломе совершенно хорошего пользовательского кода. В настоящее время мы гораздо строже о обратной совместимости в рамках основного выпуска (например, вдоль 2.*
линия, и отдельно вдоль 3.*
один, хотя несовместимости are разрешено между 2 и 3-действительно, это весь смысл С a 3.*
серия, позволяющ нам исправить прошлые проектные решения даже несовместимыми способами).
произвольные сравнения оказались более трудными, чем они стоят, вызывая путаницу пользователей; и группировка по типу теперь может быть легко получена, например, с помощью до sort
; таким образом, в Python 3 сравнения между объектами разных типов, если сами объекты специально не позволяют это в методах сравнения, вызывает исключение:
>>> decimal.Decimal('2.0') > 1.2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: Decimal() > float()
другими словами, в Python 3 это ведет себя именно так, как вы думаете, что это должно; но в Python 2 это не так (и никогда не будет в любом Python 2.*
).
Re 2, вы будете в порядке -- хотя, посмотрите на gmpy для того, что я надеюсь, это интересный способ преобразования двойников в дроби бесконечной точности через деревья Фари. Если цены, с которыми вы имеете дело, точны не более центов, используйте '%.2f' % x
а не repr(x)
!-)
вместо подкласса Decimal я бы использовал заводскую функцию, такую как
def to_decimal(float_price):
return decimal.Decimal('%.2f' % float_price)
так как, после производства, полученный десятичный является совершенно обычным.
сравнение больше, чем работает, потому что по умолчанию оно работает для всех объектов.
>>> 'abc' > 123
True
Decimal
правильно только потому, что он правильно следует спецификации. Был ли spec правильным подходом, это отдельный вопрос. :)
только нормальные предостережения при работе с поплавками, которые кратко суммируются: остерегайтесь крайних случаев, таких как отрицательный нуль, + / - бесконечность и NaN, не тестируйте на равенство (связанное со следующей точкой) и рассчитывайте на математику немного неточно.
>>> print (1.1 + 2.2 == 3.3)
False
Если это "правильно" - это вопрос мнения, но обоснование того, почему нет автоматического преобразования, существует в ОПТОСОЗ, и это было принято решение. Предостережение в основном заключается в том, что вы не всегда можете точно конвертировать между float и decimal. Поэтому преобразование не должно быть неявным. Если вы в своем приложении знаете, что у вас никогда не будет достаточно значительных чисел, чтобы это повлияло на вас, создание классов, которые позволяют это неявное поведение, не должно быть проблемой.
также, один из главных аргументов заключается в том, что реальных вариантов использования не существует. Вероятно, будет проще, если вы просто используете Decimal везде.