Python 3.x's sorted()
function cannot be relied on to sort heterogeneous sequences, because most pairs of distinct types are unorderable (numeric types like int
, float
, decimal.Decimal
etc. being an exception):
Python 3.4.2 (default, Oct 8 2014, 08:07:42)
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> sorted(["one", 2.3, "four", -5])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: float() < str()
In contrast, comparisons between objects that have no natural order are arbitrary but consistent in Python 2.x, so sorted()
works:
Python 2.7.8 (default, Aug 8 2014, 14:55:30)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> sorted(["one", 2.3, "four", -5])
[-5, 2.3, 'four', 'one']
In order to replicate Python 2.x's behaviour in Python 3.x, I wrote a class to use as the key
parameter to sorted()
, which relies on the fact that sorted()
is guaranteed to use only less-than comparisons:
class motley:
def __init__(self, value):
self.value = value
def __lt__(self, other):
try:
return self.value < other.value
except TypeError:
return repr(type(self.value)) < repr(type(other.value))
Example usage:
>>> sorted(["one", 2.3, "four", -5], key=motley)
[-5, 2.3, 'four', 'one']
So far, so good.
However, I've noticed a surprising behaviour when sorted(s, key=motley)
is called with certain sequences containing complex numbers:
>>> sorted([0.0, 1, (1+0j), False, (2+3j)], key=motley)
[(1+0j), 0.0, False, (2+3j), 1]
I would have expected 0.0
, False
and 1
to be in one group (because they are mutually orderable), and (1+0j)
and (2+3j)
in another (because they are of the same type). The fact that the complex numbers in this result are not only separated from each other, but one of them is sitting in the middle of a group of objects that are comparable with each other but not with it, is somewhat perplexing.
What's going on here?