Вот, пожалуйста, проверенный код. Использует while True:
для цикла и позволяет itertools.takewhile()
делать все с lines
. Когда itertools.takewhile()
достигает конца ввода, он возвращает итератор, который ничего не делает, кроме повышения StopIteration
, которое list()
просто превращается в пустой список, поэтому простой тест if not block:
обнаруживает пустой список и вырывается из цикл.
import itertools
def not_tabline(line):
return '\t' != line.rstrip('\n')
def block_generator(file):
with open(file) as lines:
while True:
block = list(itertools.takewhile(not_tabline, lines))
if not block:
break
yield block
for block in block_generator("test.txt"):
print "BLOCK:"
print block
Как отмечено в комментарии ниже, у этого есть один недостаток: если входной текст имеет две строки подряд только с символом табуляции, этот цикл прекратит обработку без чтения всего входного текста. И я не могу придумать способ справиться с этим чисто; очень жаль, что итератор, от которого вы получаете itertools.takewhile()
, использует StopIteration
и как маркер конца группы и как то, что вы получаете в конце файла. Что еще хуже, я не могу найти способ спросить объект-итератор файла, достиг ли он конца файла или нет. И что еще хуже, itertools.takewhile()
, кажется, мгновенно переводит файловый итератор в конец файла; когда я попытался переписать вышеприведенное, чтобы проверить наш прогресс, используя lines.tell()
, он уже был в конце файла после первой группы.
Я предлагаю использовать решение itertools.groupby()
. Это чище.