Документация itertools
имеет несколько рецептов, среди которых очень аккуратный рецепт с круговым приемом. Я бы также использовал ExitStack
для работы с несколькими файловыми менеджерами контекста:
from itertools import cycle, islice
from contextlib import ExitStack
# https://docs.python.org/3.8/library/itertools.html#itertools-recipes
def roundrobin(*iterables):
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
# Recipe credited to George Sakkis
num_active = len(iterables)
nexts = cycle(iter(it).__next__ for it in iterables)
while num_active:
try:
for next in nexts:
yield next()
except StopIteration:
# Remove the iterator we just exhausted from the cycle.
num_active -= 1
nexts = cycle(islice(nexts, num_active))
...
def get(self):
with open(files_list) as fl:
filenames = [x.strip() for x in fl]
with ExitStack() as stack:
files = [stack.enter_context(open(fname)) for fname in filenames]
yield from roundrobin(*files)
Хотя, возможно, лучшим вариантом является использование инверсии управления и предоставление последовательности файлов -объекты в качестве аргумента .get
, поэтому вызывающий код должен позаботиться об использовании стека выхода:
class Foo:
...
def get(self, files):
yield from roundrobin(*files)
# calling code:
foo = Foo() # or however it is initialized
with open(files_list) as fl:
filenames = [x.strip() for x in fl]
with ExitStack() as stack:
files = [stack.enter_context(open(fname)) for fname in filenames]
for line in foo.get(files):
do_something_with_line(line)