десятичное сравнение 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

Итак, мои вопросы

  1. это правильное поведение? (не вызывать исключения в ЦМП)
  2. что делать, если я получаю свой собственный класс и правый поплавковый преобразователь в основном 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 везде.