Allow key='attribute_name' to various sorting functions

25 views
Skip to first unread message

Ram Rachum

unread,
Apr 11, 2013, 6:24:00 PM4/11/13
to python...@googlegroups.com, Ram Rachum
I often want to sort objects by an attribute. It's cumbersome to do this:

    sorted(entries, key=lambda entry: entry.datetime_created)

Why not allow this instead:

    sorted(entries, key='datetime_created')

The `sorted` function can check whether the `key` argument is a string, and if so do an attribute lookup.

Since I see no other possible use of a string input to `key`, I don't see how this feature would harm anyone.

What do you think?


Thanks,
Ram.

Carl Meyer

unread,
Apr 11, 2013, 6:35:20 PM4/11/13
to python...@python.org, Ram Rachum
On 04/11/2013 04:24 PM, Ram Rachum wrote:
> I often want to sort objects by an attribute. It's cumbersome to do this:
>
> sorted(entries, key=lambda entry: entry.datetime_created)
>
> Why not allow this instead:
>
> sorted(entries, key='datetime_created')

from operator import attrgetter
sorted(entries, key=attrgetter('datetime_created'))

You can alias attrgetter to an even shorter name if you like.

Explicit utility functions are better than implicit special-case
behaviors. Why should a string be special-cased to attribute lookup
rather than, say, __getitem__ lookup?

Carl
_______________________________________________
Python-ideas mailing list
Python...@python.org
http://mail.python.org/mailman/listinfo/python-ideas

Ram Rachum

unread,
Apr 11, 2013, 6:52:57 PM4/11/13
to python...@googlegroups.com, Ram Rachum, python...@python.org
On Friday, April 12, 2013 1:35:20 AM UTC+3, Carl Meyer wrote:
On 04/11/2013 04:24 PM, Ram Rachum wrote:
> I often want to sort objects by an attribute. It's cumbersome to do this:
>
>     sorted(entries, key=lambda entry: entry.datetime_created)
>
> Why not allow this instead:
>
>     sorted(entries, key='datetime_created')

    from operator import attrgetter
    sorted(entries, key=attrgetter('datetime_created'))

You can alias attrgetter to an even shorter name if you like.

That's still cumbersome in my opinion.
 

Explicit utility functions are better than implicit special-case
behaviors. Why should a string be special-cased to attribute lookup 
rather than, say, __getitem__ lookup?

Right, these are options too. I'd guess that attribute lookup is more common, but maybe I'm wrong.

Donald Stufft

unread,
Apr 11, 2013, 6:54:50 PM4/11/13
to Ram Rachum, python...@python.org, python...@googlegroups.com
Special cases aren't special enough to break the rules.

-----------------
Donald Stufft
PGP: 0x6E3CBCE93372DCFA // 7C6B 7C5D 5E2B 6356 A926 F04F 6E3C BCE9 3372 DCFA

signature.asc

Oscar Benjamin

unread,
Apr 11, 2013, 7:05:38 PM4/11/13
to Ram Rachum, python-ideas
On 11 April 2013 23:52, Ram Rachum <ram.r...@gmail.com> wrote:
> On Friday, April 12, 2013 1:35:20 AM UTC+3, Carl Meyer wrote:
>>
>> On 04/11/2013 04:24 PM, Ram Rachum wrote:
>> > I often want to sort objects by an attribute. It's cumbersome to do
>> > this:
>> >
>> > sorted(entries, key=lambda entry: entry.datetime_created)
>> >
>> > Why not allow this instead:
>> >
>> > sorted(entries, key='datetime_created')
>>
>> from operator import attrgetter
>> sorted(entries, key=attrgetter('datetime_created'))
>>
>> You can alias attrgetter to an even shorter name if you like.
>
> That's still cumbersome in my opinion.

I don't think it's that cumbersome. Leaving aside the import line
you're only having to specify two things for your key function: that
it's an attribute (attrgetter) and the name of the attribute
('datetime_created'). It's not possible for this to be any more
succinct without using special case implicit rules which are generally
a bad thing. I like the fact that the API for the sorted function is
so simple I can remember all of its arguments and exactly what they do
without ever needing to look it up.


Oscar

Haoyi Li

unread,
Apr 11, 2013, 7:33:10 PM4/11/13
to Oscar Benjamin, Ram Rachum, python-ideas
A more generic and useful thing would be kind of what scala/groovy have: shorthands for defining function literals:

Groovy: 
myList.sort{it.startTime}

Scala: 
myList.sort(_.startTime)

Where "_.startTime" and "it.startTime" are shorthand for "x => x.startTime" or python's "lambda x: x.startTime". You could probably get something similar in python:

sorted(entries, key = x.datetime_created)

if you did some magic with x to make looking up an attribute return a lambda that returns that attribute of its argument.

-Haoyi

Ram Rachum

unread,
Apr 11, 2013, 7:38:28 PM4/11/13
to Haoyi Li, python-ideas
Interesting!

Oscar Benjamin

unread,
Apr 11, 2013, 7:39:30 PM4/11/13
to Haoyi Li, Ram Rachum, python-ideas
On 12 April 2013 00:33, Haoyi Li <haoy...@gmail.com> wrote:
> A more generic and useful thing would be kind of what scala/groovy have:
> shorthands for defining function literals:
>
> Groovy:
> myList.sort{it.startTime}
>
> Scala:
> myList.sort(_.startTime)
>
> Where "_.startTime" and "it.startTime" are shorthand for "x => x.startTime"
> or python's "lambda x: x.startTime". You could probably get something
> similar in python:
>
> sorted(entries, key = x.datetime_created)
>
> if you did some magic with x to make looking up an attribute return a lambda
> that returns that attribute of its argument.

You can do that if you want to:

import operator
class X(object):
def __getattribute__(self, attrname):
return operator.attrgetter(attrname)
def __getitem__(self, index):
return operator.itemgetter(index)
x = X()

Steven D'Aprano

unread,
Apr 11, 2013, 7:48:57 PM4/11/13
to python...@python.org
On 12/04/13 08:24, Ram Rachum wrote:
> I often want to sort objects by an attribute. It's cumbersome to do this:
>
> sorted(entries, key=lambda entry: entry.datetime_created)
>
> Why not allow this instead:
>
> sorted(entries, key='datetime_created')
>
> The `sorted` function can check whether the `key` argument is a string, and
> if so do an attribute lookup.

Why an attribute lookup? Why not a key lookup?

Using a trivial lambda makes it obvious what you want:

key=lambda obj: obj.name
key=lambda obj: obj[name]

and is more convenient (although probably slower) than the alternatives:

key=operator.attrgetter(name)
key=operator.itemgetter(name)


without ambiguity or guessing what the caller intended. It also avoids masking
TypeError errors if you call with a non-literal argument that happens to be a
string.

If we allow sorted etc. to guess what the caller wants with strings, should it
also guess what they want with integers?

key=3 equivalent to key=lambda obj: obj[3]

Hmmm... tempting... that would make sorting tuples by a specific field really
easy, which is an extremely common use case, and unlike strings, there's no
ambiguity.


So... -1 on allowing key='string' shortcuts, +0 on allowing key=3 shortcuts.



--
Steven

João Bernardo

unread,
Apr 11, 2013, 7:58:50 PM4/11/13
to Ram Rachum, python-ideas
You can have something like that with this module I created:
from funcbuilder import f
sorted(entries, key=f.datetime_created)


Some features in this module are very experimental, but are also very cool...


João Bernardo


2013/4/11 Ram Rachum <ram.r...@gmail.com>

Ram Rachum

unread,
Apr 11, 2013, 8:07:18 PM4/11/13
to João Bernardo, python-ideas
Awesome module!

João Bernardo

unread,
Apr 11, 2013, 8:14:10 PM4/11/13
to Ram Rachum, python-ideas
It was something I did for fun, so I never had the time to add proper documentation.
You can see the best examples to use by reading the doctests from __init__ .

BTW, It abuses a lot of Python 3 constructions, so you can't use Python 2.x


Carlo Pires

unread,
Apr 11, 2013, 8:31:06 PM4/11/13
to João Bernardo, Ram Rachum, python-ideas
Very crafty! I liked the idea of funcbuilder f as replacement for lambdas and the result is true pythonic!


2013/4/11 João Bernardo <jbv...@gmail.com>



--
  Carlo Pires

Stephen J. Turnbull

unread,
Apr 12, 2013, 2:12:42 AM4/12/13
to Donald Stufft, python...@googlegroups.com, Ram Rachum, python...@python.org
Donald Stufft writes:

> Special cases aren't special enough to break the rules.

Not to mention:

In the face of ambiguity, refuse to guess.

N.B. This is part of why Steven d'A changes from -1 to +0 on "key=3".

This looks like POSIX sort(1), and cut(1), a bit, doesn't it.

Antoine Pitrou

unread,
Apr 12, 2013, 4:41:03 AM4/12/13
to python...@python.org
Le Fri, 12 Apr 2013 09:48:57 +1000,
Steven D'Aprano <st...@pearwood.info> a
écrit :

>
> If we allow sorted etc. to guess what the caller wants with strings,
> should it also guess what they want with integers?
>
> key=3 equivalent to key=lambda obj: obj[3]
>
> Hmmm... tempting... that would make sorting tuples by a specific
> field really easy, which is an extremely common use case, and unlike
> strings, there's no ambiguity.
>
>
> So... -1 on allowing key='string' shortcuts, +0 on allowing key=3
> shortcuts.

-1 on both :-)

Regards

Antoine.

Yuval Greenfield

unread,
Apr 12, 2013, 6:26:40 AM4/12/13
to Antoine Pitrou, python-ideas
On Fri, Apr 12, 2013 at 11:41 AM, Antoine Pitrou <soli...@pitrou.net> wrote:
Le Fri, 12 Apr 2013 09:48:57 +1000,
Steven D'Aprano <st...@pearwood.info> a
écrit :
> So... -1 on allowing key='string' shortcuts, +0 on allowing key=3
> shortcuts.

-1 on both :-)



Make that a -2 on both.


Yuval 

Ram Rachum

unread,
Apr 12, 2013, 2:21:28 PM4/12/13
to Markus Unterwaditzer, python...@googlegroups.com
That would work for me, +1. (Though I imagine this idea will be showered with -1 from ebd...)


On Fri, Apr 12, 2013 at 9:19 PM, Markus Unterwaditzer <mar...@unterwaditzer.net> wrote:
>------------------------------------------------------------------------

>
>_______________________________________________
>Python-ideas mailing list
>Python...@python.org
>http://mail.python.org/mailman/listinfo/python-ideas

I think it's a very bad idea to try to overload the key argument, imo a separate kwarg of sorted would be fine though. E.g:

sorted(iterable, attribute='someattr')

-- Markus (from phone)

Markus Unterwaditzer

unread,
Apr 12, 2013, 2:21:10 PM4/12/13
to Ram Rachum, python...@python.org

Markus Unterwaditzer

unread,
Apr 12, 2013, 2:28:20 PM4/12/13
to Ram Rachum, python...@python.org
Although i think it's better to use attrgetter, since it is more easily reusable and so on.

-- Markus (from phone)

Lorenzo Bolla

unread,
Apr 12, 2013, 3:40:35 PM4/12/13
to python...@googlegroups.com
Sorting by attribute can be easily done with:

sorted(entries, key=attrgetter('datetime_created'))

L.
> --
>
> ---
> You received this message because you are subscribed to the Google Groups "python-ideas" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to python-ideas...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>

--
Lorenzo Bolla
http://lbolla.info
Reply all
Reply to author
Forward
0 new messages