[Python-ideas] Adding list.pluck()

150 views
Skip to first unread message

Cenk Altı

unread,
Jun 1, 2012, 5:10:03 PM6/1/12
to Python...@python.org
Hello All,

pluck() is a beautiful function which is in underscore.js library.
Described as "A convenient version of what is perhaps the most common
use-case for map: extracting a list of property values."

http://documentcloud.github.com/underscore/#pluck

What about it implementing for python lists? And maybe for other iterables?
_______________________________________________
Python-ideas mailing list
Python...@python.org
http://mail.python.org/mailman/listinfo/python-ideas

Oleg Broytman

unread,
Jun 1, 2012, 5:16:30 PM6/1/12
to python...@python.org
On Sat, Jun 02, 2012 at 12:10:03AM +0300, Cenk Alt?? <cenk...@gmail.com> wrote:
> pluck() is a beautiful function which is in underscore.js library.
> Described as "A convenient version of what is perhaps the most common
> use-case for map: extracting a list of property values."
>
> http://documentcloud.github.com/underscore/#pluck
>
> What about it implementing for python lists? And maybe for other iterables?

Like operator.attrgetter?
http://docs.python.org/library/operator.html#operator.attrgetter

Oleg.
--
Oleg Broytman http://phdru.name/ p...@phdru.name
Programmers don't die, they just GOSUB without RETURN.

Mike Graham

unread,
Jun 1, 2012, 5:18:45 PM6/1/12
to Cenk Altı, Python...@python.org
On Fri, Jun 1, 2012 at 5:10 PM, Cenk Altı <cenk...@gmail.com> wrote:
> Hello All,
>
> pluck() is a beautiful function which is in underscore.js library.
> Described as "A convenient version of what is perhaps the most common
> use-case for map: extracting a list of property values."
>
> http://documentcloud.github.com/underscore/#pluck
>
> What about it implementing for python lists? And maybe for other iterables?

Using a generator expression or list comprehension to do this is so
easy and readable I don't see why we'd want something new in Python.

Mike

Alexandre Zani

unread,
Jun 1, 2012, 5:25:24 PM6/1/12
to python...@python.org
What if it's a list of objects instead of a list of dicts? List
comprehension already makes this easy:

[i['name'] for i in l]

I don't think this would add as much in python as it adds in javascript.

Cenk Altı

unread,
Jun 1, 2012, 5:48:04 PM6/1/12
to Alexandre Zani, python...@python.org
l.pluck('name') is more readable IMO.

Alexandre Zani

unread,
Jun 1, 2012, 6:53:48 PM6/1/12
to Cenk Altı, python...@python.org
I must confess that I don't find "pluck" a very intuitive name for
this functionality. For me it was evocative of what pop currently
does. That's an N of 1 so maybe I'm just wrong on that one.

More importantly, this would make the use of a list method dependent
upon the type of the contained items. (works for dicts and nothing
else) That would be unprecedented for list methods and potentially
confusing. What would be the behavior if the list contains non-dicts?

Mike Meyer

unread,
Jun 1, 2012, 7:07:04 PM6/1/12
to python...@python.org
On Sat, 2 Jun 2012 00:48:04 +0300
Cenk Altı <cenk...@gmail.com> wrote:

> l.pluck('name') is more readable IMO.

Only because you already associate "pluck" with that meaning.

As others said, "pluck" to me implies something like "pop". The list
comprehension spelling doesn't suffer from this problem, and provides
a lot more flexibility. If you don't like list comprehensions, use map
and the operator module.

Even if it is more readable, it's more semantic load. It's another
container operator (and one that's only useful in the special case of
a list of maps) people have to learn. Since it saves 0 lines of code
over either of existing mechanisms, the extra load comes for no
advantage.

-1

<mike
--
Mike Meyer <m...@mired.org> http://www.mired.org/
Independent Software developer/SCM consultant, email for more information.

O< ascii ribbon campaign - stop html mail - www.asciiribbon.org

Jerry Hill

unread,
Jun 1, 2012, 7:16:37 PM6/1/12
to python...@python.org
On Fri, Jun 1, 2012 at 5:48 PM, Cenk Altı <cenk...@gmail.com> wrote:
> l.pluck('name') is more readable IMO.

That's not how the library you linked to works, as far as I can tell.
Based on the sample usage at
http://documentcloud.github.com/underscore/#pluck, pluck is a
function taking an iterable of dictionaries and the key, so I think
the python equivalent is:

def pluck(iterable, key):
return [item[key] for item in iterable]

stooges = [{'name' : 'moe', 'age' : 40},
{'name' : 'larry', 'age' : 50},
{'name' : 'curly', 'age' : 60}]

print (pluck(stooges, 'name'))

>>>
['moe', 'larry', 'curly']

--
Jerry

Cenk Altı

unread,
Jun 2, 2012, 1:25:13 AM6/2/12
to Alexandre Zani, python...@python.org
If the item has definded a method "__getitem__" it will be called,
else "__getattribute__" is called.

I know list comprehensions are same thing but .pluck seems easier to
read and write I think (no need to write a temporary variable in list
comprehension, and also square brackets). Just an idea...

Masklinn

unread,
Jun 2, 2012, 10:54:44 AM6/2/12
to Cenk Altı, python...@python.org
On 2 juin 2012, at 07:25, Cenk Altı <cenk...@gmail.com> wrote:

> If the item has definded a method "__getitem__" it will be called,
> else "__getattribute__" is called.
>

That is complète insanity and goes against pretty much all existing python code. Some types make keys available as both items and attributes but I do not know of any operation which does so.

> I know list comprehensions are same thing but .pluck seems easier to
> read and write I think (no need to write a temporary variable in list
> comprehension, and also square brackets). Just an idea...

Not a useful one, if you dislike the iteration variable of comprehensions you may use 'map' with itemgetter or attrgetter. Not to mention they are more flexible than pluck (they can extract multiple items or attributes, and attrgetter supports "deep" dotted paths)

Mathias Panzenböck

unread,
Jun 2, 2012, 11:54:50 AM6/2/12
to python...@python.org
There are already at least two easy ways to do this:

>>> stooges=[{'name': 'moe', 'age': 40}, {'name': 'larry', 'age': 50}, {'name': 'curly', 'age': 60}]
>>> [guy['name'] for guy in stooges]


['moe', 'larry', 'curly']

>>> from operator import itemgetter
>>> map(itemgetter('name'),stooges)


['moe', 'larry', 'curly']

Also I'm used to such functions being called "collect" (Ruby) or "map" (Python, jQuery) and
accepting a function/block as an argument. In Ruby-on-Rails it can be &:name as a shorthand for
{|item| item[:name]}, which is equivalent to itemgetter('name') in Python. So if you insist of
making it shorter (but less readable) you could do:

>>> from operator import itemgetter as G
>>> map(G('name'),stooges)


['moe', 'larry', 'curly']

Guido van Rossum

unread,
Jun 2, 2012, 12:06:56 PM6/2/12
to Mathias Panzenböck, python...@python.org
Forgive the out of context drive-by comments...

On Sat, Jun 2, 2012 at 8:54 AM, Mathias Panzenböck
<grosser.me...@gmx.net> wrote:
> There are already at least two easy ways to do this:
>
>>>> stooges=[{'name': 'moe', 'age': 40}, {'name': 'larry', 'age': 50},
>>>> {'name': 'curly', 'age': 60}]
>>>> [guy['name'] for guy in stooges]
> ['moe', 'larry', 'curly']

Bingo. Doesn't need improvements.

>>>> from operator import itemgetter
>>>> map(itemgetter('name'),stooges)
> ['moe', 'larry', 'curly']

If I saw this I would have to think a lot harder before I figured what
it meant. (Especially without the output example.)

Let's remember KISS.

--
--Guido van Rossum (python.org/~guido)

Calvin Spealman

unread,
Jun 2, 2012, 12:28:52 PM6/2/12
to Cenk Altı, Python...@python.org
On Fri, Jun 1, 2012 at 5:10 PM, Cenk Altı <cenk...@gmail.com> wrote:
> Hello All,
>
> pluck() is a beautiful function which is in underscore.js library.
> Described as "A convenient version of what is perhaps the most common
> use-case for map: extracting a list of property values."
>
> http://documentcloud.github.com/underscore/#pluck
>
> What about it implementing for python lists? And maybe for other iterables?

This is a case where a simple list comprehension or generator
expression would be a lot easier to understand than remembering what a
rarely used method name does. Also, it couples two distinct
interfaces, iterables and mappings, in a way that is generally frowned
upon in Python.

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

--
Read my blog! I depend on your acceptance of my opinion! I am interesting!
http://techblog.ironfroggy.com/
Follow me if you're into that sort of thing: http://www.twitter.com/ironfroggy

Serhiy Storchaka

unread,
Jun 2, 2012, 2:01:53 PM6/2/12
to python...@python.org
On 02.06.12 19:06, Guido van Rossum wrote:
> On Sat, Jun 2, 2012 at 8:54 AM, Mathias Panzenböck
> <grosser.me...@gmx.net> wrote:
>>>>> from operator import itemgetter
>>>>> map(itemgetter('name'),stooges)
>> ['moe', 'larry', 'curly']
>
> If I saw this I would have to think a lot harder before I figured what
> it meant. (Especially without the output example.)

And this is not true in Python 3.

<map object at 0xb747970c>

Westley Martínez

unread,
Jun 2, 2012, 2:50:21 PM6/2/12
to python...@python.org
On Sat, Jun 02, 2012 at 09:01:53PM +0300, Serhiy Storchaka wrote:
> On 02.06.12 19:06, Guido van Rossum wrote:
> >On Sat, Jun 2, 2012 at 8:54 AM, Mathias Panzenböck
> ><grosser.me...@gmx.net> wrote:
> >>>>>from operator import itemgetter
> >>>>>map(itemgetter('name'),stooges)
> >>['moe', 'larry', 'curly']
> >
> >If I saw this I would have to think a lot harder before I figured what
> >it meant. (Especially without the output example.)
>
> And this is not true in Python 3.
>
> <map object at 0xb747970c>

map returns a generator in Python 3.

Mathias Panzenböck

unread,
Jun 2, 2012, 3:54:56 PM6/2/12
to python...@python.org
On 06/02/2012 08:50 PM, Westley Martínez wrote:
> On Sat, Jun 02, 2012 at 09:01:53PM +0300, Serhiy Storchaka wrote:
>> On 02.06.12 19:06, Guido van Rossum wrote:
>>> On Sat, Jun 2, 2012 at 8:54 AM, Mathias Panzenböck
>>> <grosser.me...@gmx.net> wrote:
>>>>>> >from operator import itemgetter
>>>>>>> map(itemgetter('name'),stooges)
>>>> ['moe', 'larry', 'curly']
>>>
>>> If I saw this I would have to think a lot harder before I figured what
>>> it meant. (Especially without the output example.)
>>
>> And this is not true in Python 3.
>>
>> <map object at 0xb747970c>
>
> map returns a generator in Python 3.

Yes, yes. I opened a Python 2 shell to write the example code. Python 2 is still the default in most
(all?) Linux distributions. To get a list from that just wrap list() around it.

I consider this behaviour (that map returns a generator) in fact superior to what's available in
other languages. You can then pass that to whatever constructor you like (e.g. set() or tuple()) or
take only some of the values and then stop without calculating (and allocating) it all.

-panzi
Reply all
Reply to author
Forward
0 new messages