Search code examples
pythongenerator

Continue to other generators once a generator has been exhausted in a list of generators?


I have a list of generators in a function alternate_all(*args) that alternates between each generator in the list to print their first item, second item, ..., etc. until all generators are exhausted.

My code works until a generator is exhausted and once the StopIteration occurs, it stops printing, when I want it to continue with the rest of the generators and ignore the exhausted one:

def alternate_all(*args):
    iter_list = []
    for iterable in args:
        iter_list.append(iter(iterable))
    try:
        while True:
            for iterable in iter_list:
                val = next(iter_list[0])
                iter_list.append(iter_list.pop(0))
                yield val
    except StopIteration:
        pass

            
if __name__ == '__main__':
    for i in alternate_all('abcde','fg','hijk'):
        print(i,end='')

My output is:

afhbgic

When it should be:

afhbgicjdke

How can I get this to ignore the exhausted generator? I would prefer not to use itertools and keep this same structure.


Solution

  • This works. I tried to stay close to how your original code works (though I did replace your first loop with a list comprehension for simplicity).

    def alternate_all(*args):
        iter_list = [iter(arg) for arg in args]
        while iter_list:
            i = iter_list.pop(0)
            try:
                val = next(i)
            except StopIteration:
                pass
            else:
                yield val
                iter_list.append(i)
    

    The main problem with your code was that your try/except was outside of the loop, meaning the first exhausted iterator would exit from the loop. Instead, you want to catch StopIteration inside the loop so you can keep going, and the loop should keep going while iter_list still has any iterators in it.