itertools.product 是不是懒惰地评估它的论点?
Posted
技术标签:
【中文标题】itertools.product 是不是懒惰地评估它的论点?【英文标题】:Does itertools.product evaluate its arguments lazily?itertools.product 是否懒惰地评估它的论点? 【发布时间】:2017-08-09 09:34:10 【问题描述】:以下内容在 Python 3.6 中从不打印任何内容
from itertools import product, count
for f in product(count(), [1,2]):
print(f)
相反,它只是坐在那里烧 CPU。问题似乎是product
永远不会返回一个迭代器,如果它在一个无限的空间,因为它首先评估完整的product
。考虑到 product
应该是一个生成器,这令人惊讶。
我原以为这会开始计数(到无穷大),类似于这个生成器的行为(取自 directly from the docs):
for tup in ((x,y) for x in count() for y in [1,2]):
print(tup)
但是,虽然我的生成器会立即开始计数,但使用 product
的生成器根本不会计数。
itertools
中的其他工具符合我的预期。例如:
for f in takewhile(lambda x: True, count()):
print(f)
将打印一个数字流,因为takewhile
是惰性的。
【问题讨论】:
DeepSpace 的回答具有误导性:据我所知,产品 not 是懒惰的,因为它需要(我假设)无限时间才能返回,而文档按我的预期做。 【参考方案1】:itertools.product
懒惰地生成它的结果,但对于参数来说并非如此。他们被热切地评估。每个可迭代参数首先转换为一个元组:
参数的评估(不是结果的产生)与文档中显示的 Python 实现非常相似:
...
pools = [tuple(pool) for pool in args] * repeat
而在CPython implementation 中,pools
是一个元组的元组:
for (i=0; i < nargs ; ++i)
PyObject *item = PyTuple_GET_ITEM(args, i);
PyObject *pool = PySequence_Tuple(item); /* here */
if (pool == NULL)
goto error;
PyTuple_SET_ITEM(pools, i, pool);
indices[i] = 0;
之所以如此,是因为product
有时需要多次遍历一个可迭代对象,如果将参数保留为只能使用一次的迭代器,这是不可能的。
您实际上无法从 itertools.count
对象构建元组。在传递给product
之前,考虑使用itertools.islice
切片到合理的长度。
【讨论】:
这个答案让我免于使用 python 提交错误报告,做得好。【参考方案2】:问题似乎是产品从不返回迭代器
不,product
已经“懒惰”了。
问题是count()
计数到无穷大。
来自count
的docs:
相当于:
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
你的代码和做的基本一样:
def count():
i = 0
while True:
yield i
i += 1
count()
【讨论】:
我很困惑,循环不应该开始计数(到无穷大)吗?问题是它没有从count
返回任何东西
我添加了一个示例,我可以从惰性求值函数中得到我期望的结果。
@Shep count()
被评估首先,其余的代码永远不会到达,可以这么说
Count 返回一个迭代器,评估它只需要很少的时间。
好的,所以直接从文档中获取:“product(A, B)
返回与 ((x,y) for x in A for y in B)
相同的结果。”当A
是count()
时,我认为这不是真的【参考方案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
中的一个错误,但考虑到它的标准,这似乎不太可能。
【讨论】:
以上是关于itertools.product 是不是懒惰地评估它的论点?的主要内容,如果未能解决你的问题,请参考以下文章
计算 itertools.product() 的第 n 个结果