1. Python / Говнокод #21235

    +4

    1. 1
    2. 2
    ipdb> Decimal('10000') < "1"
    True

    Запостил: kosolapovdg, 22 Сентября 2016

    Комментарии (39) RSS

    • В тройке пофикшено:

      >>> Decimal('10000') < "1"
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
      TypeError: unorderable types: decimal.Decimal() < str()
      Ответить
    • А почему True, интересно? Потому что operator < (...) { return !operator>=(...); } ?
      Ответить
      • Обычно operator>(a, b) реализуют как operator<(b, a).
        Ответить
    • При этом
      >>> Decimal('10000').__lt__('1')
      NotImplemented
      потому что
      .   def __lt__(self, other, context=None):
              other = _convert_other(other, allow_float=True)
              if other is NotImplemented:
                  return other
              ans = self._compare_check_nans(other, context)
              if ans:
                  return False
              return self._cmp(other) < 0
      Напитоноэксперты, откуда взялся True?

      Строгая типизация, ага. Зачем райзить ошибки, если можно просто вовзращать мусор. Это же не цикл какой-нибудь, чтобы исключения бросать.
      Ответить
      • Похоже, интерпретатор делает неявный каст после "богатых сравнений":

        A rich comparison method may return the singleton NotImplemented if it does not implement the operation for a given pair of arguments. By convention, False and True are returned for a successful comparison. However, these methods can return any value, so if the comparison operator is used in a Boolean context (e.g., in the condition of an if statement), Python will call bool() on the value to determine if the result is true or false.

        -- https://docs.python.org/2/reference/datamodel.html#specialnames
        Ответить
        • Т.е. как цикл остановить - они исключение кидают, а когда сравнение не реализовано - возвращают какую-то херню, которая ещё и без ошибок кастуется в True...

          З.Ы. Это даже круче чем php'шный strpos, который может вернуть и 0 и FALSE.
          Ответить
        • Так в твоей пасте написано, что в bool кастится только когда надо. Откуда в репле касту взяться?
          Ответить
          • Там вообще какая-то хуйня происходит (во втором)... Я написал сейчас в repl'е Foo() < Bar() и оператор __lt__ у Foo(), который возвращает NotImplemented, позвался джважды с одними и теми же объектами... А в ответе показало True.

            http://ideone.com/b1LvRv
            Ответить
            • А Foo и Bar - это что? Если старые классы, то у их объектов одинаковый тип (<type 'instance'>) и сравниваются адреса вроде. Если новые классы, то сравниваются типы лексико-графически.
              Ответить
              • > сравниваются адреса
                А нахуя тогда оператор __lt__ позвали, да ещё и два раза? :)
                Второй раз - а вдруг передумает и True/False вернёт?
                Ответить
              • http://ideone.com/PnjOdw
                Хм, и правда для новых классов ответ совсем другой...
                Ответить
                • Реквестирую в тред трактователя питоньего стандарта.
                  Ответить
                • Можно взять для "фитон: фрактал плохого дизайна"
                  Ответить
            • Ответить
        • Похоже, я понял.

          Для питона всё же есть существенная разница между сравнением и вызовом __lt__. Сравнение в конечном итоге триггерит вызов PyObject_RichCompare, который уже конвертит результат в бул, вероятно, вызывая в данном случае try_3way_to_rich_compare, который вызывает __lt__, но остаётся недоволен результатом
          https://github.com/python/cpython/blob/2.7/Objects/object.c#L896
          Ответить
          • Я до конца не понял, но это твое объяснение объясняет вот такой результат? http://ideone.com/khUJJA
            Ответить
            • > но это твое объяснение объясняет вот такой результат?

              В теории да: в конечном итоге тут должен вызваться default_3way_compare, который тупо сравнивает имена классов
              https://github.com/python/cpython/blob/2.7/Objects/object.c#L794
              И "Decimal" как раз меньше "str". Но без дебаггера сложно сказать точно, а дальше ковыряться в этом говне запала не хватает.
              Ответить
              • >И "Decimal" как раз меньше "str".
                Лол, это тут уже где-то обсуждалось. Можете поискать в тредах где я писал.
                Ответить
      • Вот на стековерфлове пишут, что сравнение инта с каким-нибудь другим типом - implementation defined. Так что можно считать, что True там от верблюда.
        http://stackoverflow.com/a/3270689
        Ответить
        • хахахаха
          UB в моем пистончике

          мусор на входе -- мусор на выходе

          как в сишечке
          Ответить
        • > сравнение инта с каким-нибудь другим типом - implementation defined
          Неправильно. Сравнение любых объектов разных типов - implementation defined. Вот в мане написано https://docs.python.org/2/library/stdtypes.html#comparisons
          > Objects of different types, except different numeric types and different string types, never compare equal; such objects are ordered consistently but arbitrarily

          А инты к топику вообще отношения не имеют. Не знаю, зачем я про них написал.
          Ответить
        • http://stackoverflow.com/a/2384139

          Без пруфов, но человек расписал нахуя так было сделано.
          Ответить

    Добавить комментарий