itertools.product是否会延迟评估其参数?

发布于 2021-01-29 18:19:41

以下内容在Python 3.6中从不打印任何内容

from itertools import product, count

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

相反,它只是坐在那里烧坏了CPU。问题似乎在于,product如果迭代器位于无限空间内,则永远不会返回迭代器,因为它product首先评估完整的迭代器。鉴于product假设应该是发电机,这令人惊讶。

我本来希望这会开始计数(到无穷大),就像这个生成器的行为(直接从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懒惰,将打印数字流。

关注者
0
被浏览
50
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    itertools.product懒惰地生成其结果,但是对于参数而言并非如此。他们受到热切评价。每个可迭代的参数都首先转换为元组:

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

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

    而在CPython实现中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对象构建元组。在传递给之前,请考虑 将切片
    至的合理长度。itertools.islice``product



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看