Is there a way in python to change the order in which yield from get's processed? [duplicate]

我与影子孤独终老i 提交于 2019-12-02 00:11:36

You are trying to zip() your iterators; do so explicitly:

from itertools import chain

def foo():
    yield from chain.from_iterable(zip(range(10), range(10, 20)))

The use of itertools.chain.from_iterable() lets you continue to use yield from here, flattening out the tuples zip() produces.

Demo:

>>> from itertools import chain
>>> def foo():
...     yield from chain.from_iterable(zip(range(10), range(10, 20)))
... 
>>> list(foo())
[0, 10, 1, 11, 2, 12, 3, 13, 4, 14, 5, 15, 6, 16, 7, 17, 8, 18, 9, 19]

If you have generators of different lengths, you could use itertools.zip_longest():

from itertools import zip_longest

def foo():
    yield from (i for pair in zip_longest(range(10), range(10, 22))
                  for i in pair if i is not None)

I used a different flattening technique here with a double loop in a generator expression.

This all does get tedious, and since you are not using yield from with another generator (so you don't need support for generator.send() and generator.throw() to be propagated), you may as well just make this a proper loop:

def foo():
    for x, y in zip_longest(range(10), range(10, 22)):
        if x is not None:
            yield x
        if y is not None:
            yield y            

You can also use the roundrobin() recipe listed in the itertools documentation recipies section:

from itertools import cycle

def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    # Recipe credited to George Sakkis
    pending = len(iterables)
    nexts = cycle(iter(it).__next__ for it in iterables)
    while pending:
        try:
            for next in nexts:
                yield next()
        except StopIteration:
            pending -= 1
            nexts = cycle(islice(nexts, pending))

def foo():
    yield from roundrobin(range(10), range(10, 22))
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!