views:

498

answers:

3

I'd like to read at most 20 lines from a csv file:

rows = [csvreader.next() for i in range(20)]

Works fine if the file has 20 or more rows, fails with a StopIteration exception otherwise.

Is there an elegant way to deal with an iterator that could throw a StopIteration exception in a list comprehension or should I use a regular for loop?

+8  A: 

You can use itertools.islice. It is the iterator version of list slicing. If the iterator has less than 20 elements, it will return all elements.

import itertools
rows = list(itertools.islice(csvreader, 20))
Ayman Hourieh
Thanks Ayman. It seems like list comprehensions need to be updated to deal with StopIteration, no? It appears "for" has already been updated to deal with it (it stops iterating when it encounters the exception, implicitly catching it), and I'm not seeing an obvious reason for list comprehensions not to do the same.
Parand
for catches the StopIteration relative to its iterable, not to other such objects in its suite. For instancec = iter(range(5))for i in range(10): print i, c.next()will raise the StopIteration exception relative to c.
Mapio
A for loop does NOT implicitly catch StopIteration. It only catches it if it is thrown by the iterator's next method, not if it is thrown in the loop body. In your question, csvreader.next() is analogous to the loop body.
Miles
<1 second late! *shakes fist* ;)
Miles
That's fair, you guys are right. I guess my construct is a bit funky, iterating over the counter instead of the csv iterable, so the exception really should cause a stoppage.
Parand
A: 

If for whatever reason you need also to keep track of the line number, I'd recommend you:

rows = zip(xrange(20), csvreader)

If not, you can strip it out after or... well, you'd better try other option more optimal from the beginning :-)

fortran
If you need the line number, surely you should use enumerate() ..
John Fouhy
A: 

itertools.izip (2) provides a way to easily make list comprehensions work, but islice looks to be the way to go in this case.

from itertools import izip
[row for (row,i) in izip(csvreader, range(20))]
outis