Вот элегантное решение:
def alternate(*iterators):
while len(iterators) > 0:
try:
yield next(iterators[0])
# Move this iterator to the back of the queue
iterators = iterators[1:] + iterators[:1]
except StopIteration:
# Remove this iterator from the queue completely
iterators = iterators[1:]
Использование реальной очереди для лучшей производительности (как предложено Дэвидом):
from collections import deque
def alternate(*iterators):
queue = deque(iterators)
while len(queue) > 0:
iterator = queue.popleft()
try:
yield next(iterator)
queue.append(iterator)
except StopIteration:
pass
Это работает, даже когда некоторые итераторы конечны, а другие бесконечны:
from itertools import count
for n in alternate(count(), iter(range(3)), count(100)):
input(n)
Печать:
0
0
100
1
1
101
2
2
102
3
103
4
104
5
105
6
106
Также корректно останавливается, если / когда все итераторы были исчерпаны.
Если вы хотите обрабатывать не итераторы, такие как списки, вы можете использовать
def alternate(*iterables):
queue = deque(map(iter, iterables))
...