I inadvertently typed time.clock<()
with the Python 2.7 interpreter response being: True
. The following code exemplifies the behavior:
In Python 2, when comparing different types, python sorts numeric types before everything else, and between the rest sorts types by type name.
Thus, integers sort before tuples, but instances of class Foo
will sort after instances of class Bar
.
Python 3 does away with this madness; comparing different types results in a TypeError instead:
>>> 10 < ()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: int() < tuple()
The Python set()
type has overloaded the >
operator by implementing the __gt__ or 'greater then' magic method; it is called for the 1 < set()
expression because the int
type has no __lt__
, lower-then and Python tests the inverse in that case; after all, x < y
is true if y > x
is true.
The set.__gt__()
hook raises a TypeError
when the other operand is not a set
:
>>> 1 .__lt__(set())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute '__lt__'
>>> set().__gt__(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only compare to a set
The overloaded >
(greater then) operator for sets is used to test if the left-hand operand is a proper superset of the right-hand operand. (Technically, set
objects implement the C-API PyTypeObject.tp_richcompare function, not the __gt__
hook directly, but the __gt__
hook translates to a tp_richcompare
call in that case automatically).
When an overloaded comparison method (one of .__lt__(), .__le__(), .__eq__(), . __ne__(), . __gt__(), . __ge__(), or . __cmp__()) returns the NotImplemented
singleton object this signals that the comparison is not supported and Python falls back to the default behaviour. This default behaviour, as already stated in How do Python comparison operators < and > work with a function name as an operand? differs between Python 2 and 3.
For Python 3, a comparison hook returning NotImplemented
causes Python to raise TypeError
:
>>> class Foo():
... def __lt__(self, other): return NotImplemented
...
>>> Foo() < Foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: Foo() < Foo()
Python 2 is more stubborn and when NotImplemented
is returned or no hooks have been implemented, the C code ends up in the default_3way_compare() C function, which:
None
before anything (line 780-783)PyNumber_Check
tests set type name to empty, lines 786-793)v->ob_type->tp_name
and w->ob_type->tp_name
in lines 786-793)