473,387 Members | 1,834 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

When is List Comprehension inappropriate?

Ben
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.

Thanks,
Ben

Mar 19 '07 #1
14 1549
Ben <be********@gmail.comwrote:
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
Mar 19 '07 #2
On Mar 19, 9:41 am, "Ben" <bensher...@gmail.comwrote:
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)]
To simplify access to individual pixels, you can make even2 into a
dict using:

even2asDict = dict(even2)

and then you can directly get the pixel in the 4th row, 5th column
(zero-based) as:

even2asDict[(4,5)]

If you really want something more like a 2-D array, then create a list
comp of lists, as in:

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

which allows you to use list indexing to get individual pixel values,
as in:

even2[4][5]

to get the same pixel as above.

-- Paul

Mar 19 '07 #3
On 19 Mar 2007 07:41:59 -0700, Ben <be********@gmail.comwrote:
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)]
I would definitely not use list comprehension in this case. While they
may be faster, Psyco is great here. Also, if you have lots of 2d-loops
like "for x in something: for y in something:", then it could be more
beautiful to separate the iteration from the task:

def iterimage(im, width, height, step = 1):
for y in range(0, height, step):
for x in range(0, width, step):
yield (x, y), im.getpixel((x, y))

Then the list comprehension becomes a little more manageable:

even2 = [(pos, col) for pos, col in iterimage(im, width, height, 2)]

Although this must definitely be the slowest of all the different approaches.

--
mvh Björn
Mar 19 '07 #4
"Ben" <be********@gmail.comwrote:
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)]
....
>
Feel free to tell me a different way to do this, as well.
Untested code, but I would try to avoid calling getpixel:

data = list(im.getdata())
width, height = im.size
even = [ data[i:i+width:2] for i in range(0, width*height, 2*width)]

That creates a 2 dimensional list rather than one long list, and doesn't
create the x,y tuples, but since they are implied by the position in the
list I don't actually see why you would want to create them at all. You can
calculate them separately if you actually need them.
Mar 19 '07 #5
On Mon, 19 Mar 2007 07:41:59 -0700, Ben 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.
Others have suggested reasons why you might or might not want to use list
comprehensions. Here's three more reasons:

* You have a LOT of data to handle. (But remember that a lot to you might
not be a lot to your computer.)

* You don't need to handle the items all at once, and can handle the items
one at a time instead.

Use an iterator, generator expression, or other lazily-evaluated function
instead. That way you avoid forming the list all at once.

* You have to write code that's backwards-compatible to an old version of
Python.

Use a list and a for-loop.

--
Steven.

Mar 20 '07 #6
BJörn Lindqvist <bj*****@gmail.comwrote:
...
even2 = [(pos, col) for pos, col in iterimage(im, width, height, 2)]
list(iterimage(etc etc))

is surely a better way to express identical semantics. More generally,
[x for x in whatever] (whether x is a single name or gets peculiarly
unpacked and repacked like here) is a good example of inappropriate LC,
to get back to the question in the subject: list(whatever) is the "one
obvious way" to perform the same task.
Alex
Mar 20 '07 #7
BJörn Lindqvist:
While they
may be faster, Psyco is great here. Also, if you have lots of 2d-loops
like "for x in something: for y in something:", then it could be more
beautiful to separate the iteration from the task:

def iterimage(im, width, height, step = 1):
for y in range(0, height, step):
for x in range(0, width, step):
yield (x, y), im.getpixel((x, y))
Just a note: Psyco usually isn't able to speed up generators (ShedSkin
recently has hadded a support of them too, and it seem fast enough).

Bye,
bearophile

Mar 20 '07 #8
Alex Martelli wrote:
BJörn Lindqvist <bj*****@gmail.comwrote:
...
>even2 = [(pos, col) for pos, col in iterimage(im, width, height, 2)]

list(iterimage(etc etc))

is surely a better way to express identical semantics. More generally,
[x for x in whatever] (whether x is a single name or gets peculiarly
unpacked and repacked like here) is a good example of inappropriate LC,
to get back to the question in the subject: list(whatever) is the "one
obvious way" to perform the same task.
Clearly the comprehension you complain about is sub-optimal.

The essential difference, however, is between

[x for x in iterimage(im, width, height, 2)]

and

list(iterimage(im, width, height, 2))

I agree that the latter is the obvious way, but the difference isn't as
large as your leap makes it look - and we had to await the invention of
the generator expression for it to be a practical choice.

regards
Steve
--
Steve Holden +44 150 684 7255 +1 800 494 3119
Holden Web LLC/Ltd http://www.holdenweb.com
Skype: holdenweb http://del.icio.us/steve.holden
Recent Ramblings http://holdenweb.blogspot.com

Mar 20 '07 #9
In article <1h***************************@mac.com>,
Alex Martelli <al***@mac.comwrote:
>
list(iterimage(etc etc))

is surely a better way to express identical semantics. More generally,
[x for x in whatever] (whether x is a single name or gets peculiarly
unpacked and repacked like here) is a good example of inappropriate LC,
to get back to the question in the subject: list(whatever) is the "one
obvious way" to perform the same task.
Except of course, when it's

[x for x in whatever if x]

I'm exceedingly fond of replacing filter() with listcomps. They're so
much more readable and often faster.
--
Aahz (aa**@pythoncraft.com) <* http://www.pythoncraft.com/

"Typing is cheap. Thinking is expensive." --Roy Smith
Mar 20 '07 #10
Aahz <aa**@pythoncraft.comwrote:
In article <1h***************************@mac.com>,
Alex Martelli <al***@mac.comwrote:

list(iterimage(etc etc))

is surely a better way to express identical semantics. More generally,
[x for x in whatever] (whether x is a single name or gets peculiarly
unpacked and repacked like here) is a good example of inappropriate LC,
to get back to the question in the subject: list(whatever) is the "one
obvious way" to perform the same task.

Except of course, when it's

[x for x in whatever if x]

I'm exceedingly fond of replacing filter() with listcomps. They're so
much more readable and often faster.
Sure, if there are other clauses in the LC (be they for or if ones) you
can't just call list(...) -- and I do entirely agree that filter can be
put out to pasture. Similarly, you need the LC if you're performing
some processing on the items -- for example, if you have an iterator
yielding pairs,
[(y,x) for x,y in whatever]
you do need the unpacking and repacking to achieve this swapping of
items within each pair -- what I was pointing out was re the simpler and
most common case:
[(x,y) for x,y in whatever]
no processing needed, no if clauses, etc, and thus better expressed as
list(whatever)
Alex
Mar 20 '07 #11
On Mar 19, 2:41 pm, "Ben" <bensher...@gmail.comwrote:
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.

Thanks,
Ben
I have found that I have gone too far when I used listcomps for their
sideeffects rather than wanting the list produced, for example the
second listcomp below is an expression as statement I don't want the
list produced - just the effect on data.
>># some random ranges
data = [range(random.randrange(3,7)) for x in range(4)]
# but I want each range jumbled
[ random.shuffle(d) for d in data]
[None, None, None, None]
>>data
[[2, 0, 3, 1], [0, 2, 1], [3, 4, 1, 0, 2], [2, 1, 0, 3]]
>>>
(I do know how to re-write it).

- Paddy.

Mar 21 '07 #12
Steve Holden <st***@holdenweb.comwrites:
Alex Martelli wrote:
BJörn Lindqvist <bj*****@gmail.comwrote:
...
even2 = [(pos, col) for pos, col in iterimage(im, width, height, 2)]
list(iterimage(etc etc))
is surely a better way to express identical semantics. More
generally,
[x for x in whatever] (whether x is a single name or gets peculiarly
unpacked and repacked like here) is a good example of inappropriate LC,
to get back to the question in the subject: list(whatever) is the "one
obvious way" to perform the same task.
Clearly the comprehension you complain about is sub-optimal.

The essential difference, however, is between

[x for x in iterimage(im, width, height, 2)]

and

list(iterimage(im, width, height, 2))

I agree that the latter is the obvious way, but the difference isn't
as large as your leap makes it look - and we had to await the
invention of the generator expression for it to be a practical choice.
What generator expression? I don't see a genexp in your examples.
John
Mar 21 '07 #13
Paddy <pa*******@googlemail.comwrote:
...
I have found that I have gone too far when I used listcomps for their
sideeffects rather than wanting the list produced, for example the
I agree.
second listcomp below is an expression as statement I don't want the
list produced - just the effect on data.
># some random ranges
data = [range(random.randrange(3,7)) for x in range(4)]
# but I want each range jumbled
[ random.shuffle(d) for d in data]
[None, None, None, None]
>data
[[2, 0, 3, 1], [0, 2, 1], [3, 4, 1, 0, 2], [2, 1, 0, 3]]
>>

(I do know how to re-write it).
for d in data: random.shuffle(d)
Alex
Mar 22 '07 #14
On Mar 22, 4:56 am, a...@mac.com (Alex Martelli) wrote:
Paddy <paddy3...@googlemail.comwrote:

...
I have found that I have gone too far when I used listcomps for their
sideeffects rather than wanting the list produced, for example the

I agree.
second listcomp below is an expression as statement I don't want the
list produced - just the effect on data.
>># some random ranges
>>data = [range(random.randrange(3,7)) for x in range(4)]
>># but I want each range jumbled
>>[ random.shuffle(d) for d in data]
[None, None, None, None]
>>data
[[2, 0, 3, 1], [0, 2, 1], [3, 4, 1, 0, 2], [2, 1, 0, 3]]
(I do know how to re-write it).

for d in data: random.shuffle(d)

Alex
Hah,
"You just couldn't let it lie" ;-)

I just knew someone would bite, and re-write it.
Now to reel, you in. Its fish for dinner today!
- Paddy.

Mar 22 '07 #15

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

23
by: Fuzzyman | last post by:
Pythons internal 'pointers' system is certainly causing me a few headaches..... When I want to copy the contents of a variable I find it impossible to know whether I've copied the contents *or*...
18
by: a | last post by:
can someone tell me how to use them thanks
4
by: Gregory Guthrie | last post by:
Sorry for a simple question- but I don't understand how to parse this use of a list comprehension. The "or" clauses are odd to me. It also seems like it is being overly clever (?) in using a...
6
by: rkmr.em | last post by:
Hi I need to process a really huge text file (4GB) and this is what i need to do. It takes for ever to complete this. I read some where that "list comprehension" can fast up things. Can you point...
4
by: bullockbefriending bard | last post by:
Given: class Z(object): various defs, etc. class ZList(list): various defs, etc. i would like to be able to replace
11
by: beginner | last post by:
Hi, Does anyone know how to put an assertion in list comprehension? I have the following list comprehension, but I want to use an assertion to check the contents of rec_stdl. I ended up using...
10
by: Debajit Adhikary | last post by:
I have two lists: a = b = What I'd like to do is append all of the elements of b at the end of a, so that a looks like: a =
4
by: beginner | last post by:
Hi All, If I have a list comprehension: ab= c = "ABC" print c
1
by: Ken Pu | last post by:
Hi all, I observed an interesting yet unpleasant variable scope behaviour with list comprehension in the following code: print print x It outputs:
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.