Если у вас есть только итератор, и вам нужно выполнить два вида обработки на нем, не занимая слишком много памяти, лучше всего спроектировать обработку, которую вы выполняете для параллельной работы. То есть вы должны иметь возможность выполнять обе части обработки по одному элементу за раз. В вашем примере обе ваши итераторские функции просто распечатывали его, что не очень хорошо подходит для распараллеливания (вы получите распечатку в другом порядке, например 1, 1, 2, 2, 3, 3, ...
). Но для других типов проблем легко выполнить часть работы, а затем ждать больше данных.
Вот пример, где я использую две функции генератора для параллельного использования итератора tee
(используя встроенный zip
). Один складывает полученные значения и печатает только окончательную сумму, а другой печатает их индивидуально.
def consume1(it):
total = 0
for value in it:
total += value
yield
print(total)
def consume2(it):
for value in it:
print(value)
yield
opaque_iterator = iter((1, 2, 3, 4))
it1, it2 = itertools.tee(opaque_iterator)
for _ in zip(consume1(it1), consume2(it2)):
pass
Вывод:
1
2
3
4
10
Существует множество тонкостей такого рода кода, так что не удивляйтесь, если вы не получите его с первой попытки. Мой код выше выглядит как agile, так как zip
на самом деле не предназначен для управления такими генераторами, как этот.