¿Por qué 0 <() evalúa a True en Python?

Sin querer, time.clock<() con la respuesta del intérprete de Python 2.7 siendo: True . El siguiente código ejemplifica el comportamiento:

 >>> repr(time.clock) '' >>> time.clock<() True 

Además:

 >>> import sys >>> sys.maxint >> map(lambda _:0<_,((),[],{})) [True, True, True] 

A diferencia de:

 >>> 1<set(()) TypeError: can only compare to a set 

Pregunta: Además de por qué, ¿hay un significado o propósito práctico de una list vacía, tuple o dict evalúa como si fuera mayor que cualquier número?


Actualización :

    • Viktor señaló que las direcciones de memoria se comparan por defecto:

      >>> map(lambda _:(id(0),'<',id(_)),((),[],{}, set([])))

      [(31185488L, '<', 30769224L), (31185488L, '<', 277144584L), (31185488L, '<', 279477880L), (31185488L, '<', 278789256L)]

    A pesar del orden aparente, esto es incorrecto .


    • Martijn Pieters señala que:

    Sin un operador de comparación explícito definido, Python 2 se compara por Números y Nombres de tipo, con los números con la prioridad más baja.

    Esto no sugiere qué métodos internos exactos se están invocando. Vea también este útil pero no concluyente hilo de SO :

    En un IPython 2.7.5 REPL

     >>> type(type(()).__name__) Out[15]: str >>> type(()) >> 10 >> type(()) >> type(()) == type(()) Out[10]: True However: >>> 'somestr' .__le__(10) Out[20]: NotImplemented >>> 'somestr' .__lt__(10) Out[21]: NotImplemented >>> int.__gt__ Out[25]:  >>> int.__lt__ Out[26]:  >>> int.__lt__(None) Out[27]: NotImplemented #.....type(...), dir(...), type, dir...... #An 'int' instance does not have an >> 0 .__lt__ Out[28]: AttributeError: 'int' object has no attribute '__lt__' #int is actually a subclass of bool >>>int.__subclasses__() Out: [bool] #str as the fallback type for default comparisons >>> type(''.__subclasshook__) Out[72]: builtin_function_or_method >>> dir(''.__subclasshook__) Out[73]: ['__call__', '__class__', '__cmp__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__'] #IPython is subclassing 'str' >>> str.__subclasses__() Out[84]: [IPython.utils.text.LSString] 

    En Python 2, cuando se comparan diferentes tipos, python ordena los tipos numéricos antes que todo lo demás, y entre el rest clasifica los tipos por tipo de nombre .

    Por lo tanto, los enteros se ordenan antes de las tuplas, pero las instancias de la clase Foo se ordenarán después de las instancias de la clase Bar .

    Python 3 elimina esta locura; comparando diferentes tipos de resultados en un TypeError en su lugar:

     >>> 10 < () Traceback (most recent call last): File "", line 1, in  TypeError: unorderable types: int() < tuple() 

    El tipo set() Python ha sobrecargado el operador > al implementar el método mágico __gt__ o 'mayor que'; se llama para la expresión 1 < set() porque el tipo int no tiene __lt__ , lower-then y Python prueba el inverso en ese caso; después de todo, x < y es verdadero si y > x es verdadero.

    El gancho del set.__gt__() genera un TypeError cuando el otro operando no es un set :

     >>> 1 .__lt__(set()) Traceback (most recent call last): File "", line 1, in  AttributeError: 'int' object has no attribute '__lt__' >>> set().__gt__(1) Traceback (most recent call last): File "", line 1, in  TypeError: can only compare to a set 

    El operador sobrecargado > (mayor que) para los conjuntos se usa para probar si el operando de la izquierda es un superconjunto apropiado del operando de la derecha . (Técnicamente, los objetos set implementan la función PyTypeObject.tp_richcompare C-API, no el __gt__ directamente, pero el __gt__ traduce en una llamada tp_richcompare en ese caso automáticamente).

    Cuando un método de comparación sobrecargado (uno de .__lt__() , .__le__() , .__eq__() . __ne__() . __gt__() . __ge__() , o . __cmp__() ) devuelve el objeto singleton No NotImplemented este indica que la comparación no es compatible y Python vuelve al comportamiento predeterminado. Este comportamiento predeterminado, como ya se indicó en ¿Cómo funcionan los operadores de comparación de Python con un nombre de función como un operando? Se diferencia entre Python 2 y 3.

    Para Python 3, un NotImplemented comparación que devuelve NotImplemented hace que Python NotImplemented TypeError :

     >>> class Foo(): ... def __lt__(self, other): return NotImplemented ... >>> Foo() < Foo() Traceback (most recent call last): File "", line 1, in  TypeError: unorderable types: Foo() < Foo() 

    Python 2 es más terco y cuando se devuelve NotImplemented o no se han implementado enganches, el código C termina en la función default_3way_compare() C , que:

    • Pedidos por direcciones de memoria cuando los tipos de ambos objetos son los mismos (línea 768-776)
    • Pedidos None antes de nada (línea 780-783)
    • Ordena los números antes que otros tipos ( PyNumber_Check prueba que el nombre del tipo esté vacío, líneas 786-793)
    • Pedidos por nombre de tipo ( v->ob_type->tp_name y w->ob_type->tp_name en las líneas 786-793)
    • Si los nombres de los tipos son iguales, los pedidos por dirección de memoria de los objetos de tipo (líneas 800 y 801).