Як Python 2 порівнює рядки та int? Чому списки порівнюються як числа, а числа, а кортежі більше, ніж списки?


178

Наступний фрагмент позначається результатом ( як видно на ideone.com ):

print "100" < "2"      # True
print "5" > "9"        # False

print "100" < 2        # False
print 100 < "2"        # True

print 5 > "9"          # False
print "5" > 9          # True

print [] > float('inf') # True
print () > []          # True

Чи може хтось пояснити, чому вихід такий?


Деталі реалізації

  • Чи така поведінка обумовлена ​​специфікацією мови, чи це залежить від виконавців?
  • Чи є відмінності між будь-якими основними реалізаціями Python?
  • Чи є відмінності між версіями мови Python?

23
З 3000 дуплів цього питання на це є відповідь, що пояснює, чому мова була розроблена таким чином (і чому вона була перероблена в 3.x). Це не є частиною цього питання, але є частиною багатьох питань, які тут пов'язані.
abarnert

Відповіді:


209

З посібника python 2 :

Деталі реалізації CPython: Об'єкти різних типів, крім чисел, упорядковуються за їх назвами типів; об'єкти одного типу, які не підтримують належне порівняння, упорядковуються за їхньою адресою.

При замовленні двох рядків або двох числових типів упорядкування виконується очікуваним способом (лексикографічне впорядкування рядків, впорядкування чисел для цілих чисел).

Коли ви замовляєте числовий і нечисловий тип, на перше місце виходить числовий тип.

>>> 5 < 'foo'
True
>>> 5 < (1, 2)
True
>>> 5 < {}
True
>>> 5 < [1, 2]
True

Коли ви замовляєте два несумісні типи, де жоден не є числовим, вони впорядковуються в алфавітному порядку їх назв:

>>> [1, 2] > 'foo'   # 'list' < 'str' 
False
>>> (1, 2) > 'foo'   # 'tuple' > 'str'
True

>>> class Foo(object): pass
>>> class Bar(object): pass
>>> Bar() < Foo()
True

Один виняток - класи старого стилю, які завжди стоять перед класами нового стилю.

>>> class Foo: pass           # old-style
>>> class Bar(object): pass   # new-style
>>> Bar() < Foo()
False

Чи така поведінка обумовлена ​​специфікацією мови, чи це залежить від виконавців?

Немає мовної специфікації . Посилання на мову говорить:

В іншому випадку об'єкти різних типів завжди порівнюють неоднаково і впорядковуються послідовно, але довільно.

Отже, це деталь реалізації.

Чи є відмінності між будь-якими основними реалізаціями Python?

Я не можу відповісти на це, тому що я використовував лише офіційну реалізацію CPython, але є й інші реалізації Python, такі як PyPy.

Чи є відмінності між версіями мови Python?

У Python 3.x поведінку було змінено так, що спроба впорядкувати ціле число та рядок призведе до помилки:

>>> '10' > 5
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    '10' > 5
TypeError: unorderable types: str() > int()

55
Це добре, що вони змінили його в Py3k. Коли я вперше побачив це питання, мої думки були «що, це не викликає помилок?».
JAL

9
Примітка. Винятком із правила 2.x, що різні типи впорядковуються за назвою типу, полягає в тому, що об'єкт None порівнюється як менший, ніж кожен інший тип. У порівнянні з 3.x порівняння None з іншим типом все одно підніме TypeError.
Дейв Кірбі

4
@KarelBilek: bool є числовим типом. І True == 1, так що це ні <, ні>.
abarnert

3
Лексографічний порядок назв їх типів? Коли ви хочете, щоб це було особливістю? Хто б коли-небудь цим скористався?
Джек

3
Факт забави: complex(1,0) > 'abc'є, Falseале complex(1,0) > complex(0,0)піднімаєTypeError
Ерік Дюмініл

24

Рядки мають по порівнянні лексично, і різнорідні типи порівнюються по імені їх типу ( "int"< "string"). 3.x фіксує другу точку, роблячи їх непорівнянними.


3
Але в python2 int менше, ніж дикти, тож це не може бути просто лексикографічно за назвою типу?
Тоні Суффолк 66,

Я щойно натрапив на цю відповідь і погоджуюся з Тоні Суффолк. Об'єкти НЕ упорядковуються назвою типу, коли вони не відрізняються.
Exelian

@ Числовий тип TonySuffolk66 є винятком із цього правила. NumericType завжди нижчий, ніж будь-який інший тип (крім NoneType) у 2.7.
лів
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.