From: Ben Finney on
Howdy all,

Python 2.6 tells me that, in Python 3, sorting a list with entries of
incompatible types is not allowed:

=====
$ python2.5 -c "foo = [1, True, 'green', 4, -27, 15.3]; foo.sort(); print foo;"
[-27, 1, True, 4, 15.300000000000001, 'green']

$ python2.6 -c "foo = [1, True, 'green', 4, -27, 15.3]; foo.sort(); print foo;"
[-27, 1, True, 4, 15.300000000000001, 'green']

$ python2.6 -3 -c "foo = [1, True, 'green', 4, -27, 15.3]; foo.sort(); print foo;"
-c:1: DeprecationWarning: comparing unequal types not supported in 3.x
[-27, 1, True, 4, 15.300000000000001, 'green']
=====

So how should I be sorting a list with entries of “unequal types” such
that it will work in Python 3?

--
\ “The idea that He would take his attention away from the |
`\ universe in order to give me a bicycle with three speeds is |
_o__) just so unlikely that I can't go along with it.” —Quentin Crisp |
Ben Finney
From: Peter Otten on
Ben Finney wrote:

> Python 2.6 tells me that, in Python 3, sorting a list with entries of
> incompatible types is not allowed:

> $ python2.6 -3 -c "foo = [1, True, 'green', 4, -27, 15.3]; foo.sort();
> print foo;" -c:1: DeprecationWarning: comparing unequal types not
> supported in 3.x
> [-27, 1, True, 4, 15.300000000000001, 'green']
> =====
>
> So how should I be sorting a list with entries of “unequal types” such
> that it will work in Python 3?

I can't find the relevant part of the 2.6 documentation, but something like

>>> def key(x):
.... t = type(x)
.... t = compat.get(t, t)
.... return t.__name__, id(t), x
....
>>> compat = {bool: float, int: float}
>>> sorted([1, True, 'green', 4, -27, 15.3], key=key)
[-27, 1, True, 4, 15.300000000000001, 'green']

should work.

Peter
From: Paul Rubin on
Ben Finney <ben+python(a)benfinney.id.au> writes:
> So how should I be sorting a list with entries of “unequal types” such
> that it will work in Python 3?

Um, what ordering do you want? Basically you have to write a custom key
function (they removed the option of writing a comparison function).

Maybe something like

foo.sort(key=lambda x: (type(x), x))

would be enough to fool the sorting function? I don't have python 3
so I haven't tried it.
From: MRAB on
Ben Finney wrote:
> Howdy all,
>
> Python 2.6 tells me that, in Python 3, sorting a list with entries of
> incompatible types is not allowed:
>
> =====
> $ python2.5 -c "foo = [1, True, 'green', 4, -27, 15.3]; foo.sort(); print foo;"
> [-27, 1, True, 4, 15.300000000000001, 'green']
>
> $ python2.6 -c "foo = [1, True, 'green', 4, -27, 15.3]; foo.sort(); print foo;"
> [-27, 1, True, 4, 15.300000000000001, 'green']
>
> $ python2.6 -3 -c "foo = [1, True, 'green', 4, -27, 15.3]; foo.sort(); print foo;"
> -c:1: DeprecationWarning: comparing unequal types not supported in 3.x
> [-27, 1, True, 4, 15.300000000000001, 'green']
> =====
>
> So how should I be sorting a list with entries of “unequal types” such
> that it will work in Python 3?
>
First you need to decide how they should be ordered, for example by name
of class then value.

Then make tuple keys for the values. Python compares tuple members
one by one, only looking at the next members if the current members are
equal, so if the first members are the class names (str) and the second
members are the values (possibly unequal types), then Python will
compare the values only if the types are the same.

>>> sorted([1, True, 'green', 4, -27, 15.3], key=lambda value:
(type(value).__name__, value))
[True, 15.3, -27, 1, 4, 'green']

This does mean that Boolean < float < int, but that's easy to fix:

>>> def make_key(value):
.... if isinstance(value, (int, float)):
.... return "float", float(value)
.... return type(value).__name__, value
....
>>> sorted([1, True, 'green', 4, -27, 15.3], key=make_key)
[-27, 1, True, 4, 15.3, 'green']
From: MRAB on
Paul Rubin wrote:
> Ben Finney <ben+python(a)benfinney.id.au> writes:
>> So how should I be sorting a list with entries of “unequal types” such
>> that it will work in Python 3?
>
> Um, what ordering do you want? Basically you have to write a custom key
> function (they removed the option of writing a comparison function).
>
> Maybe something like
>
> foo.sort(key=lambda x: (type(x), x))
>
> would be enough to fool the sorting function? I don't have python 3
> so I haven't tried it.

You can't compare types:

TypeError: unorderable types: type() < type()

but you can compare their names.