Jak Python 2 porównuje ciąg znaków i int? Dlaczego listy są większe niż liczby, a krotki większe niż listy?

178

Poniższy fragment kodu jest opatrzony adnotacjami do wyniku ( jak widać na 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

Czy ktoś może wyjaśnić, dlaczego dane wyjściowe są takie?


Szczegóły dotyczące wdrożenia

  • Czy takie zachowanie jest wymagane przez specyfikację języka, czy też zależy od implementatorów?
  • Czy są jakieś różnice między głównymi implementacjami języka Python?
  • Czy istnieją różnice między wersjami języka Python?
środki smarujące wielotlenowe
źródło
23
Spośród 3000 dups to pytanie, ten ma odpowiedź wyjaśniającą , dlaczego język został zaprojektowany w ten sposób (i dlaczego został ponownie zaprojektowany w 3.x). To nie jest część tego pytania, ale jest częścią wielu pytań, które tutaj się łączą.
abarnert

Odpowiedzi:

209

Z podręcznika Python 2 :

Szczegóły implementacji CPython: Obiekty różnych typów oprócz liczb są uporządkowane według nazw typów; obiekty tego samego typu, które nie obsługują właściwego porównania, są uporządkowane według ich adresu.

Kiedy zamawiasz dwa ciągi lub dwa typy liczbowe, porządkowanie odbywa się w oczekiwany sposób (porządek leksykograficzny dla ciągu, porządek numeryczny dla liczb całkowitych).

Kiedy zamawiasz numeryczny i nieliczbowy typ, numeryczny jest na pierwszym miejscu.

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

Gdy zamawiasz dwa niezgodne typy, w których żaden nie jest numeryczny, są one uporządkowane według kolejności alfabetycznej ich nazw typów:

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

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

Jedynym wyjątkiem są klasy w starym stylu, które zawsze poprzedzają klasy w nowym stylu.

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

Czy takie zachowanie jest wymagane przez specyfikację języka, czy też zależy od implementatorów?

Nie ma specyfikacji języka . Odniesienia język mówi:

W przeciwnym razie obiekty różnych typów zawsze porównują nierówne i są uporządkowane konsekwentnie, ale arbitralnie.

Jest to więc szczegół implementacji.

Czy są jakieś różnice między głównymi implementacjami języka Python?

Nie mogę odpowiedzieć na to pytanie, ponieważ użyłem tylko oficjalnej implementacji CPython, ale są też inne implementacje Pythona, takie jak PyPy.

Czy istnieją różnice między wersjami języka Python?

W Pythonie 3.x zachowanie zostało zmienione, dlatego próba zamówienia liczby całkowitej i ciągu spowoduje zgłoszenie błędu:

>>> '10' > 5
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    '10' > 5
TypeError: unorderable types: str() > int()
Mark Byers
źródło
55
Dobrze, że zmienili to w Py3k. Kiedy po raz pierwszy zobaczyłem to pytanie, pomyślałem: „co, to nie powoduje błędu?”.
JAL
9
Uwaga: Wyjątkiem od reguły 2.x, że różne typy są uporządkowane według nazwy typu, jest to, że obiekt Brak zawsze porównuje mniej niż każdy inny typ. W wersji 3.x porównanie None z innym typem nadal wywoła błąd TypeError.
Dave Kirby,
4
@KarelBilek: bool jest typem numerycznym. I Prawda == 1, więc nie jest to ani <ani>.
abarnert
3
Kolejność leksykalna nazw ich typów? Kiedy chciałbyś, żeby to była funkcja? Kto by tego użył?
Jack
3
Ciekawostka: complex(1,0) > 'abc'to Falsejednak complex(1,0) > complex(0,0)rodziTypeError
Eric Duminil
24

Ciągi porównywane leksykograficznie, a różne typy są porównywane według nazwy ich typu ( "int"< "string"). 3.x naprawia drugi punkt, czyniąc je nieporównywalnymi.

Ignacio Vazquez-Abrams
źródło
3
Ale w python2 int są mniej niż dykta, więc nie można po prostu leksykograficznie według nazwy typu?
Tony Suffolk 66
Właśnie natrafiłem na tę odpowiedź i zgadzam się z Tony'm Suffolkiem. Obiekty NIE są uporządkowane według nazwy typu, gdy są niepodobne.
Exelian
@ TonySuffolk66 typ liczbowy jest wyjątkiem od tej reguły. NumericType jest zawsze niższy niż jakikolwiek inny typ (z wyjątkiem NoneType) w wersji 2.7.
lef