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