Class-override of a sort-key method?

Steve Holden steve at holdenweb.com
Mon Dec 20 20:50:28 EST 2010


On 12/20/2010 7:10 PM, Chris Rebert wrote:
> On Mon, Dec 20, 2010 at 3:23 PM,  <pythonlist.calin79 at spamgourmet.com> wrote:
>> Hi all - it would seem that these days, all the cool kids use the sort
>> function's 'key' kwarg in order to sort a list of custom objects quickly.
> 
> Really? They don't bother to define __cmp__ or similar? Sounds lazy
> and poorly structured.
> 
That sounds to me like a potentially ill-informed response.

>> Unfortunately, as opposed to using 'cmp', where you can implent __cmp__ to
>> get 'automatic sorting' in a similar fashion, there doesn't seem to be a
>> direct analogue for a class-overridable method for providing a sort key.
>>  (ie, something like '__sortkey__' or '__key__').
> 
Why do you talk about "implementing __cmp__"? Why should this be necessary?

> Just simply delegate to key comparison in your __cmp__ (or similar) method(s).
> 
Assuming, of course, that you are conveniently sorting only object over
which you have complete control ...

>> Is there one, and I'm just missing it? If not, are there any plans to add
>> one? (I did a quick search of the PEP list, and the only hits for 'sort' I
>> saw had to do with sorting dictionaries by value).
> 
> If you know at class-definiton-time how you want instances to be
> sorted, then just define __cmp__ (or the rich comparison methods)
> appropriately, possibly even delegating to a comparison of keys (as
> the class defines them).
> 
> For example:
> 
> from functools import total_ordering
> 
> @total_ordering
> class Person(object):
>     def __init__(self, first_name, last_name):
>         self.first_name = first_name
>         self.last_name = last_name
> 
>     @property
>     def _key(self):
>         """Identifying key for a Person, by which they are sorted"""
>         return (self.last_name, self.first_name)
> 
>     def __eq__(self, other):
>         return isinstance(other, Person) and self._key == other._key
> 
>     def __lt__(self, other):
>         return self._key < other._key
> 
> If you want to abstract even this away, then just write a class
> decorator; there's no need to add yet another (rather complicated due
> to all the interactions with the existing comparison methods) special
> method.
> 
But the *real* point is (as the documentation attempts to point out)
that by providing the key argument it gets called only once per element,
whereas the cmp argument (or the objects' __cmp__() method if you insist
on letting sort delegate to that) gets called every time two objects
have to be compared. If cmp is a Python function (or equivalently if
__cmp__() is a Python method) then calling it will take much longer than
calling hte built-in default routines.

regards
 Steve
-- 
Steve Holden           +1 571 484 6266   +1 800 494 3119
PyCon 2011 Atlanta March 9-17       http://us.pycon.org/
See Python Video!       http://python.mirocommunity.org/
Holden Web LLC                 http://www.holdenweb.com/




More information about the Python-list mailing list