Python: исключение StopIteration и понимание списка

Я хотел бы прочитать не более 20 строк из файла csv:

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

Работает нормально, если в файле 20 или более строк, в противном случае происходит сбой с исключением StopIteration.

Есть ли элегантный способ работы с итератором, который может генерировать исключение StopIteration в понимании списка, или мне следует использовать обычный цикл for?


person Parand    schedule 09.07.2009    source источник


Ответы (3)


Вы можете использовать itertools.islice. Это итераторная версия нарезки списка. Если итератор имеет менее 20 элементов, он вернет все элементы.

import itertools
rows = list(itertools.islice(csvreader, 20))
person Ayman Hourieh    schedule 09.07.2009
comment
Спасибо Айман. Похоже, что необходимо обновить понимание списка, чтобы иметь дело с StopIteration, не так ли? Похоже, что он уже был обновлен, чтобы справиться с этим (он прекращает итерацию, когда встречает исключение, неявно перехватывая его), и я не вижу очевидной причины, по которой понимание списка не должно делать то же самое. - person Parand; 10.07.2009
comment
for перехватывает StopIteration относительно своего итерируемого объекта, а не других таких объектов в его наборе. Например, c = iter(range(5)) for i in range(10): print i, c.next() вызовет исключение StopIteration относительно c. - person Mapio; 10.07.2009
comment
Цикл for НЕ неявно перехватывает StopIteration. Он перехватывает его только в том случае, если он вызывается методом next итератора, а не в теле цикла. В вашем вопросе csvreader.next() аналогичен телу цикла. - person Miles; 10.07.2009
comment
‹Опоздание на 1 секунду! пожимает кулак ;) - person Miles; 10.07.2009
comment
Это честно, вы, ребята, правы. Я предполагаю, что моя конструкция немного напугана, повторяя счетчик, а не итерацию csv, поэтому исключение действительно должно вызывать остановку. - person Parand; 10.07.2009

itertools.izip (2) позволяет легко заставить работать списки, но в этом случае islice кажется подходящим вариантом.

from itertools import izip
[row for (row,i) in izip(csvreader, range(20))]
person outis    schedule 08.08.2009
comment
это имеет то преимущество, что оно не зависит от len() (например, для apsw.cursor) - person Mark; 03.06.2011
comment
enumerate - правильный способ сделать это, не сжимая диапазон. - person ArekBulski; 02.12.2015

Если по какой-либо причине вам нужно также отслеживать номер строки, я бы рекомендовал вам:

rows = zip(xrange(20), csvreader)

Если нет, то можно потом разобрать или... ну, лучше попробовать другой вариант, более оптимальный изначально :-)

person fortran    schedule 09.07.2009