11

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?

twasbrillig
  • 17,084
  • 9
  • 43
  • 67
Parand
  • 102,950
  • 48
  • 151
  • 186

3 Answers3

15

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
  • 132,184
  • 23
  • 144
  • 116
  • 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 Jul 09 '09 at 23:25
  • 2
    for catches the StopIteration relative to its iterable, not to other such objects in its suite. For instance c = iter(range(5)) for i in range(10): print i, c.next() will raise the StopIteration exception relative to c. –  Jul 09 '09 at 23:34
  • 3
    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 Jul 09 '09 at 23:34
  • 1
    <1 second late! *shakes fist* ;) – Miles Jul 09 '09 at 23:35
  • 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 Jul 09 '09 at 23:39
0

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
  • 75,655
  • 22
  • 151
  • 221
-1

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
  • 74,053
  • 25
  • 135
  • 175