做itertools.product懒惰地评估它的论点?

2024-05-16 22:32:05 发布

您现在位置:Python中文网/ 问答频道 /正文

下面的代码从未在Python3.6中打印任何内容

from itertools import product, count

for f in product(count(), [1,2]): 
    print(f)

相反,它只是坐在那里烧CPU。问题似乎是product永远不会返回迭代器,如果它在无限空间上,因为它首先计算完整的product。鉴于product应该是一个生成器,这一点令人惊讶。在

我本以为这会开始计数(到无穷大),类似于这个生成器的行为(取directly from the docs):

^{pr2}$

但是,虽然我的生成器立即开始计数,但使用product的生成器根本不计数。在

itertools中的其他工具执行我预期的操作。例如,以下内容:

for f in takewhile(lambda x: True, count()): 
    print(f)

将打印数字流,因为takewhile是惰性的。在


Tags: 代码infromimport内容forcount空间
3条回答

我发现了

for tup in ((x,y) for x in count() for y in [1,2]):
    print(tup)

做我所期望的。这很奇怪,因为它is listed as equivelent in the docs。这看起来像是itertools.product中的一个bug,但考虑到它有多标准,似乎不太可能。

The issue seems to be that product never returns an iterator

不,product已经是“懒惰”了。

问题是count()数到无穷大。 来自countdocs

相当于:

def count(start=0, step=1):
    # count(10)  > 10 11 12 13 14 ...
    # count(2.5, 0.5) -> 2.5 3.0 3.5 ...
    n = start
    while True:
        yield n
        n += step

您的代码基本上与执行以下操作相同:

^{pr2}$

^{}懒洋洋地生成结果,但对于参数来说不是这样。他们被热切地评价。每个iterable参数首先转换为一个元组:

参数的计算(不是结果的产生)与文档中显示的Python实现非常相似:

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

然而,在CPython implementation中,pools是一个元组:

^{pr2}$

这是因为product有时需要多次遍历iterable,如果将参数保留为只能使用一次的迭代器,这是不可能的。

实际上,您无法从itertools.count对象构建元组。在传递给product之前,考虑使用itertools.islice切片到合理的长度。

相关问题 更多 >