首页 > 解决方案 > 在多个生成器之间随机采样?

问题描述

我正在尝试随机迭代多个生成器,并通过从可用生成器列表中删除它们来跳过那些已经耗尽的生成器。然而,CombinedGenerator 并没有像它应该的那样调用自己来切换生成器。相反,当较小的迭代器用尽时,它会抛出一个 StopIteration。我错过了什么?

以下作品:

gen1 = (i for i in range(0, 5, 1))
gen2 = (i for i in range(100, 200, 1))

list_of_gen = [gen1, gen2]
print(list_of_gen)

list_of_gen.remove(gen1)
print(list_of_gen)

list_of_gen.remove(gen2)
print(list_of_gen)

其中每个生成器都通过它们的引用被删除。

但在这里它没有:

import random

gen1 = (i for i in range(0, 5, 1))
gen2 = (i for i in range(100, 200, 1))

total = 105

class CombinedGenerator:
    def __init__(self, generators):
        self.generators = generators

    def __call__(self):
        generator = random.choice(self.generators)

        try:
            yield next(generator)
        except StopIteration:
            self.generators.remove(generator)
            if len(self.generators) != 0:
                self.__call__()
            else:
                raise StopIteration

c = CombinedGenerator([gen1, gen2])

for i in range(total):
    print(f"iter {i}")
    print(f"yielded {next(c())}")

标签: python

解决方案


正如@Tomerikoo 提到的,您基本上是在创建自己的生成器,最好以__next__更清洁和pythonic 的方式实现。

上面的代码可以用下面的行来修复。

def __call__(self):
    generator = random.choice(self.generators)

    try:
        yield next(generator)
    except StopIteration:
        self.generators.remove(generator)
        if len(self.generators) != 0:
            # yield your self.__call__() result as well
            yield next(self.__call__())
        else:
            raise StopIteration

推荐阅读