When is List Comprehension inappropriate?

Alex Martelli aleax at mac.com
Mon Mar 19 11:01:59 EDT 2007


Ben <bensherman at gmail.com> wrote:

> I have recently learned how list comprehension works and am finding it
> extremely cool.  I am worried, however, that I may be stuffing it into
> places that it does not belong.
> 
> What's the most "pythony" way to do this:
> 
> even = []
> for x in range(0,width,2):
>     for y in range(0,height,2):
>         color = im.getpixel((x,y))
>         even.append(((x,y), color))
> 
> versus list comprehension:
> 
> even2 = [((x,y), im.getpixel((x,y))) for x in range(0,width,2) for y
> in range(0,height,2)]
> 
> Is there a computational difference in creating a blank list and
> appending to it versus doing a list comprehension?   Are there
> advantages to it outside of short and pretty code?
> 
> Feel free to tell me a different way to do this, as well.

I like list comprehensions when I'm building up a list, originally
empty, with .append calls within for loops (possibly with an if guard),
unless I need (e.g.) a conditional break, which LCs don't support.

IOW, I would use a LC in your example.  However, I would format it more
neatly:

even2 = [((x,y), im.getpixel((x,y))) 
               for x in range(0,width,2) 
               for y in range(0,height,2)]

though I guess that's a matter of taste.

Some people think that LCs should not be used except for extremely
simple cases, but I personally disagree with that stance.

The cases where an LC should NOT be used are those in which you are not
really building a list as above described, but e.g. "just looping".

To check whether LC is faster than, slower than, or equal to a more
extensive loop, use timeit, e.g.:

brain:~/py25/Doc alex$ python -mtimeit -s'xs=range(83)' 'L=[]' 'for x in
xs: L.append(x*x)'
10000 loops, best of 3: 34.6 usec per loop

brain:~/py25/Doc alex$ python -mtimeit -s'xs=range(83)' 'L=[x*x for x in
xs]' 
100000 loops, best of 3: 19.4 usec per loop

So for this simple case, it may look like the LC is much faster;
however:

brain:~/py25/Doc alex$ python -mtimeit -s'xs=range(83)'
'L=[];ap=L.append' 'for x in xs: ap(x*x)'
10000 loops, best of 3: 22.3 usec per loop

...as you can see, hoisting the L.append lookup out of the loop accounts
for most of the difference.


Alex



More information about the Python-list mailing list