Comment Python 2 compare-t-il string et int? Pourquoi les listes se comparent-elles comme supérieures aux nombres et les tuples supérieurs aux listes?

178

L'extrait suivant est annoté avec la sortie ( comme vu sur 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

Quelqu'un peut-il expliquer pourquoi le résultat est en tant que tel?


Détails d'implémentation

  • Ce comportement est-il imposé par la spécification du langage ou appartient-il aux implémenteurs?
  • Existe-t-il des différences entre les principales implémentations de Python?
  • Existe-t-il des différences entre les versions du langage Python?
lubrifiants polygènes
la source
23
Sur les 3000 dups de cette question, celle-ci a une réponse expliquant pourquoi le langage a été conçu de cette façon (et pourquoi il a été re-conçu en 3.x). Cela ne fait pas partie de cette question, mais fait partie de nombreuses questions qui sont liées ici.
abarnert

Réponses:

209

À partir du manuel de python 2 :

Détail de l'implémentation de CPython: les objets de différents types à l'exception des nombres sont classés par leur nom de type; les objets du même type qui ne prennent pas en charge la comparaison appropriée sont classés par leur adresse.

Lorsque vous commandez deux chaînes ou deux types numériques, l'ordre est effectué de la manière attendue (ordre lexicographique pour la chaîne, ordre numérique pour les entiers).

Lorsque vous commandez un type numérique et un type non numérique, le type numérique vient en premier.

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

Lorsque vous commandez deux types incompatibles où aucun n'est numérique, ils sont classés par ordre alphabétique de leurs noms de types:

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

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

Une exception concerne les classes de style ancien qui précèdent toujours les classes de style nouveau.

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

Ce comportement est-il imposé par la spécification du langage ou appartient-il aux implémenteurs?

Il n'y a pas de spécification de langue . La référence linguistique dit:

Sinon, les objets de types différents se comparent toujours de manière inégale et sont ordonnés de manière cohérente mais arbitraire.

C'est donc un détail de mise en œuvre.

Existe-t-il des différences entre les principales implémentations de Python?

Je ne peux pas répondre à celle-ci car je n'ai utilisé que l'implémentation officielle de CPython, mais il existe d'autres implémentations de Python telles que PyPy.

Existe-t-il des différences entre les versions du langage Python?

Dans Python 3.x, le comportement a été modifié de sorte que la tentative de tri d'un entier et d'une chaîne lèvera une erreur:

>>> '10' > 5
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    '10' > 5
TypeError: unorderable types: str() > int()
Mark Byers
la source
55
C'est bien qu'ils l'ont changé dans Py3k. Quand j'ai vu cette question pour la première fois, mes pensées étaient «quoi, cela ne soulève pas d'erreur?».
JAL
9
NB Une exception à la règle 2.x selon laquelle les différents types sont classés par le nom du type est que l'objet None se compare toujours comme inférieur à tous les autres types. Dans 3.x, la comparaison de None avec un autre type lèvera toujours une TypeError.
Dave Kirby
4
@KarelBilek: bool est un type numérique. Et True == 1 donc ce n'est ni <ni>.
abarnert
3
Ordre lexographique de leurs noms de types? Quand voudriez-vous que ce soit une fonctionnalité? Qui utiliserait jamais ça?
Jack
3
Fait amusant: complex(1,0) > 'abc'est Falsemais complex(1,0) > complex(0,0)soulève unTypeError
Eric Duminil
24

Les chaînes sont comparées lexicographiquement et les types différents sont comparés par le nom de leur type ( "int"< "string"). 3.x corrige le deuxième point en les rendant non comparables.

Ignacio Vazquez-Abrams
la source
3
Mais en python2, les int sont moins que des dictionnaires, donc cela ne peut pas être lexicographiquement par nom de type?
Tony Suffolk 66
Je viens de trouver cette réponse et je suis d'accord avec Tony Suffolk. Les objets ne sont PAS classés par nom de type lorsqu'ils sont différents.
Exelian
@ Le type numérique TonySuffolk66 fait exception à cette règle. NumericType est toujours inférieur à tout autre type (à l'exception de NoneType) dans 2.7.
lef