views:

3943

answers:

4

Is there a reason to prefer using map() over list comprehension or vice versa? Is one generally more effecient or generally considered more pythonic than the other?

+28  A: 

map may be microscopically faster in some cases (when you're NOT making a lambda for the purpose, but using the same function in map and a listcomp). List comprehensions may be faster in other cases and most (not all) pythonistas consider them more direct and clearer.

An example of the tiny speed advantage of map when using exactly the same function:

$ python -mtimeit -s'xs=range(10)' 'map(hex, xs)'
100000 loops, best of 3: 4.86 usec per loop
$ python -mtimeit -s'xs=range(10)' '[hex(x) for x in xs]'
100000 loops, best of 3: 5.58 usec per loop

An example of how performance comparison gets completely reversed when map needs a lambda:

$ python -mtimeit -s'xs=range(10)' 'map(lambda x: x+2, xs)'
100000 loops, best of 3: 4.24 usec per loop
$ python -mtimeit -s'xs=range(10)' '[x+2 for x in xs]'
100000 loops, best of 3: 2.32 usec per loop
Alex Martelli
better answer and interesting notes.
Paolo Bergantino
@Paolo, grazie!-)
Alex Martelli
Thanks. It sounds like list comprehensions are the way to go in most cases.
TimothyAWiseman
Yep, indeed our internal Python style guide at work explicitly recomments listcomps against map and filter (not even mentioning the tiny but measurable performance improvement map can give in some cases;-).
Alex Martelli
Not to kibash on Alex's infinite style points, but sometimes map seems easier to read to me: data = map(str, some_list_of_objects). Some other ones... operator.attrgetter, operator.itemgetter, etc.
Gregg Lind
`map(operator.attrgetter('foo'), objs)` easier to read than `[o.foo for foo in objs]` ?!
Alex Martelli
Alex, you're not as lazy as me.... I usually have "from operator import itemgetter as iget, attrgetter as aget" for that very reason!
Gregg Lind
@Alex: I prefer not to introduce unnecessary names, like `o` here, and your examples show why.
Reid Barton
+6  A: 

I find list comprehensions are generally more expressive of what I'm trying to do than map - they both get it done, but the former saves the mental load of trying to understand what could be a complex lambda expression.

There's also an interview out there somewhere (I can't find it offhand) where Guido lists lambdas and the functional functions as the thing he most regrets about accepting into Python, so you could make the argument that they're un-Pythonic by virtue of that.

Dan
Yeah, sigh, but Guido's original intention to remove lambda altogether in Python 3 got a barrage of lobbying against it, so he went back on it despite my stout support -- ah well, guess lambda's just too handy in many *SIMPLE* cases, the only problem is when it exceeds the bounds of *SIMPLE* or gets assigned to a name (in which latter case it's a silly hobbled duplicate of def!-).
Alex Martelli
+2  A: 

Here is one possible case:

map(lambda op1,op2: op1*op2, list1, list2)

versus:

[op1*op2 from op1,op2 in zip(list1,list2)]

I am guessing the zip() is an unfortunate and unnecessary overhead you need to indulge in if you insist on using list comprehensions instead of the map. Would be great if someone clarifies this whether affirmatively or negatively.

andz
"[op1*op2 from op1,op2 in zip(list1,list2)]" | s/form/for/And an equivalent list with out zip: (less readable)[list1[i]*list2[i] for i in range(len(list1))]
weakish
Should be "for" not "from" in your second code quote, @andz, and in @weakish's comment too. I thought I had discovered a new syntactical approach to list comprehensions... Darn.
vgm64
+3  A: 

Another reason to use list comprehension over map() and filter() is that Psyco can't compile these functions.

See http://psyco.sourceforge.net/psycoguide/node29.htm

Brett