Десятичное сравнение python

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

поэтому мои вопросы

  • Это правильное поведение? (не поднимать исключение в cmp)
  • Что, если я получу свой собственный класс и правый поплавковый конвертер в принципе Десятичный (repr (float_value)), являются есть ли какие-либо оговорки? мой прецедент включает только сравнение цен

Сведения о системе: Python 2.5.2 на Ubuntu 8.04.1

Ответы

Ответ 1

Re 1, это действительно то поведение, которое мы разработали - правильно или неправильно, как может быть (извините, если это отключает ваш прецедент, но мы пытались быть генералом!).

В частности, долгое время каждый объект Python мог быть подвергнут неравенству по сравнению со всеми остальными - объекты типов, которые на самом деле не сравнимы, сравниваются произвольно (последовательно в данном пробеге, а не во всех прогонах); основной вариант использования - сортировка гетерогенного списка для группировки элементов в нем по типу.

Исключение было введено только для сложных чисел, что делало их несопоставимыми ни с чем, но это было еще много лет назад, когда мы были иногда кавалером, нарушая превосходный код пользователя. В настоящее время мы гораздо более жестко поддерживаем обратную совместимость в основном выпуске (например, вдоль строки 2.* и отдельно по 3.*), хотя несовместимости разрешены между 2 и 3 - действительно, что вся точка наличия 3.*, позволяя нам исправить прошлые дизайнерские решения даже несовместимыми способами).

Произвольные сравнения оказались более трудными, чем они стоят, вызывая путаницу пользователя; и группировка по типу теперь может быть легко получена, например, с аргументом key=lambda x: str(type(x)) до 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 я бы использовал функцию factory, такую ​​как

def to_decimal(float_price):
    return decimal.Decimal('%.2f' % float_price)

так как после его создания результирующее десятичное число является совершенно обычным.

Ответ 2

Сравнение больше, чем сравнение, потому что по умолчанию оно работает для всех объектов.

>>> 'abc' > 123
True

Decimal справедлив только потому, что он правильно следует спецификации. Является ли спецификация правильным подходом, это отдельный вопрос.:)

Только обычные оговорки при работе с поплавками, которые кратко суммируются: остерегайтесь таких крайних случаев, как отрицательный ноль, +/- бесконечность и NaN, не проверяйте равенство (связанное со следующей точкой) и считайте по математике немного неточно.

>>> print (1.1 + 2.2 == 3.3)
False

Ответ 3

Если это "правильно", это вопрос мнения, но обоснование того, почему в ОПТОСОЗ нет автоматического преобразования, было принято это решение. Предостережение в основном состоит в том, что вы не всегда можете точно конвертировать между float и decimal. Поэтому преобразование не должно быть неявным. Если вы в своем приложении знаете, что у вас никогда не будет достаточно значительных чисел, чтобы это повлияло на вас, создание классов, которые допускают это неявное поведение, не должно быть проблемой.

Кроме того, одним из основных аргументов является то, что случаев использования в реальном мире не существует. Скорее всего, это будет проще, если вы просто используете десятичную таблицу везде.