Разделите генератор на куски, не проходя его предварительно.Python

Программы на Python
Ответить
Anonymous
 Разделите генератор на куски, не проходя его предварительно.

Сообщение Anonymous »

(Этот вопрос связан с этим и этим, но это предварительный обход генератора, а это именно то, чего я хочу избежать)

Я хотел бы разделить генератор на куски. Требования следующие:
  • не дополнять фрагменты: если количество оставшихся элементов меньше размера фрагмента, последний фрагмент должен быть меньше.
  • не ходите по генератору заранее: вычисление элементов требует больших затрат, и это должно выполняться только потребляющей функцией, а не чанкером
  • что означает, конечно: не накапливать в памяти (нет списков)
Я попробовал следующий код:

Код: Выделить всё

def head(iterable, max=10):
for cnt, el in enumerate(iterable):
yield el
if cnt >= max:
break

def chunks(iterable, size=10):
i = iter(iterable)
while True:
yield head(i, size)

# Sample generator: the real data is much more complex, and expensive to compute
els = xrange(7)

for n, chunk in enumerate(chunks(els, 3)):
for el in chunk:
print 'Chunk %3d, value %d' % (n, el)
И это как-то работает:

Код: Выделить всё

Chunk   0, value 0
Chunk   0, value 1
Chunk   0, value 2
Chunk   1, value 3
Chunk   1, value 4
Chunk   1, value 5
Chunk   2, value 6
^CTraceback (most recent call last):
File "xxxx.py", line 15, in 
for el in chunk:
File "xxxx.py", line 2, in head
for cnt, el in enumerate(iterable):
KeyboardInterrupt
Нуууу... оно никогда не останавливается (мне приходится нажимать ^C) из-за while True. Я хотел бы остановить этот цикл всякий раз, когда генератор потребляется, но я не знаю, как обнаружить эту ситуацию. Я попытался создать исключение:

Код: Выделить всё

class NoMoreData(Exception):
pass

def head(iterable, max=10):
for cnt, el in enumerate(iterable):
yield el
if cnt >= max:
break
if cnt == 0 : raise NoMoreData()

def chunks(iterable, size=10):
i = iter(iterable)
while True:
try:
yield head(i, size)
except NoMoreData:
break

# Sample generator: the real data is much more complex, and expensive to compute
els = xrange(7)

for n, chunk in enumerate(chunks(els, 2)):
for el in chunk:
print 'Chunk %3d, value %d' % (n, el)
Но тогда исключение возникает только в контексте потребителя, а это не то, чего я хочу (я хочу сохранить код потребителя в чистоте)

Код: Выделить всё

Chunk   0, value 0
Chunk   0, value 1
Chunk   0, value 2
Chunk   1, value 3
Chunk   1, value 4
Chunk   1, value 5
Chunk   2, value 6
Traceback (most recent call last):
File "xxxx.py", line 22, in 
for el in chunk:
File "xxxx.py", line 9, in head
if cnt == 0 : raise NoMoreData
__main__.NoMoreData()
Как определить, что генератор исчерпан в функции chunks, не проходя его?

Подробнее здесь: https://stackoverflow.com/questions/245 ... walking-it
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»