为什么itertools.product在初始化时贯穿所有元素?

问题描述 投票:3回答:1

我假设itertools.product一次生成元素。我现在注意到这是不正确的。简单的概念证明:

Class A:
  def __init__(self, n):
    self.source = iter(range(n))

  def __iter__(self):
    return self

  def __next__(self):
    val = next(self.source)
    print("I am at:", val)
    return val

现在,如果我愿意:

from itertools import product
l = product(A(3), A(3))
print("Here")
next(l)

我希望将其作为输出:

>'Here'
>'I am at 0'
>'I am at 0'

但是我有

>'I am at 0'
>'I am at 1'
>'I am at 2'
>'I am at 0'
>'I am at 1'
>'I am at 2'
>'Here'

我想念什么吗?

iteration generator python-3.7
1个回答
1
投票

要回答您的问题,我们需要查看itertools.product的实现:

def product(*args, repeat=1):
    pools = [tuple(pool) for pool in args] * repeat
    result = [[]]
    for pool in pools:
        result = [x+[y] for x in result for y in pool]
    for prod in result:
        yield tuple(prod)

关注此行代码:

pools = [tuple(pool) for pool in args] * repeat

通过这种方式,两个迭代器的所有元素(输入中)被转换为元组列表(仅在您首次调用next()时,并且此时才真正创建它们。

返回您的代码,第一次调用next(l)时,将创建迭代器的所有元素。在您的示例中,将使用以下元素创建polls列表:

# pools: [(0, 1, 2), (0, 1, 2)]

这就是为什么获得这些输出的原因。


至于print("Here"),要了解为什么首先打印它,您需要了解发生器的工作方式:

itertool.product()返回一个生成器对象。直到第一个next()刺激生成器后,生成器才执行功能代码。随后,每个调用next()都允许您计算下一个元素,只执行一次包含关键字yield的循环。

Here,您将找到优秀的资源来更好地了解python生成器的工作原理。

© www.soinside.com 2019 - 2024. All rights reserved.