与 itertools.cycle 或类似结构一起使用时的 Python“重启”生成器?

Posted

技术标签:

【中文标题】与 itertools.cycle 或类似结构一起使用时的 Python“重启”生成器?【英文标题】:Python "restart" generator when used with itertools.cycle or similar construct? 【发布时间】:2017-03-07 19:09:45 【问题描述】:

我想从生成器中产生随机值,并且我希望能够无限次地产生它们,因此我将生成器包装在 itertools.cycle 中。

下面是一个示例实现。

from itertools import cycle
import numpy as np

def generator(batch_size):
  for _ in range(batch_size):
    yield np.random.randint(0,50)

np.random.seed(111)
batch_size = 3
gen = cycle(generator(batch_size))

for _ in range(10):
  print([next(gen) for _ in range(batch_size)])

还有输出:

[20, 44, 20]
[20, 44, 20]
[20, 44, 20]
[20, 44, 20]
[20, 44, 20]
[20, 44, 20]
[20, 44, 20]
[20, 44, 20]
[20, 44, 20]
[20, 44, 20]

注意输出只是重复相同的三个数字。

我的直觉是生成器应该在每个周期开始时“重新启动”,但似乎情况并非如此。相反,生成器似乎运行一次以生成初始列表,然后无限期地重复输出。

实现所需行为的另一种策略是丢弃cycle,而是将infinite=True 参数传递给生成器,然后使用while True 循环而不是for _ in range(...) 循环:

def generator(batch_size, infinite):
  while True:
    for _ in range(batch_size):
      yield np.random.randint(0,50)
    if not infinite:
      break

但这感觉很笨拙。

是否有任何构造可用于包装生成器,以便在每个循环中实际重新启动它?

【问题讨论】:

你能解释一下为什么你试图从一个产生一批随机数的函数中构建一个无限的随机数流,而不是从其他一些原语(比如一次产生一个的函数) ? 参见Why does Python's itertools.cycle need to create a copy of the iterable? 以及itertools.cycle 的文档 @user2357112 当然,我正在从图像中随机抽样窗口来训练分类器。具体使用kerasfit_generator方法。 '只是重复相同的三个数字。'这就是循环的意思。 @PeterWood 这是真的。我更改了标题以反映我有兴趣找到可以重新启动生成器的类似构造。 【参考方案1】:

构建和展平无限的生成器流:

from itertools import chain, repeat
infinite_gen = chain.from_iterable(map(generator, repeat(batch_size)))
#                 flatten            infinite stream of generators

或者在 Python 2 上:

from itertools import chain, repeat, imap
infinite_gen = chain.from_iterable(imap(generator, repeat(batch_size)))

【讨论】:

以上是关于与 itertools.cycle 或类似结构一起使用时的 Python“重启”生成器?的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 中,为啥 itertools.cycle 需要额外的内存? [复制]

使用 itertools.cycle() 循环遍历多个列表

Itertools循环方法 - 为什么“while”循环?

python内置函数itertools

itertools模块

python 内置迭代:itertools