2017-08-09 60 views
1

下在Python 3.6从不打印任何东西itertools.product懒惰地评估它的参数吗?

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是懒惰的。

+0

DeepSpace的答案是误导性的:据我所知,产品不是懒惰,因为它需要(我假设)无限的时间来返回,而文档中的等价示例却如我所料。 – Shep

回答

4

itertools.product懒洋洋地产生了它的结果,但这对于论据来说并不正确。他们热切地被评估。每个迭代参数首先被转换为一个元组:

的参数的评估(不生产的结果)是非常类似于在该文档中示出的Python实现:

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

然而,在CPython implementationpools是元组的元组:

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

+1

这个答案救了我从python提交错误报告,做得好。 – Shep

1

这个问题似乎是,产品也不会返回一个迭代

没有,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 

您的代码基本上是一样的做:

def count(): 
    i = 0 
    while True: 
     yield i 
     i += 1 

count() 
+0

我很困惑,不应该循环开始计数(无穷大)?问题是,它不会从'count'返回任何东西# – Shep

+0

我添加了一个例子,我得到了我期望从懒惰的评估函数中得到的结果。 – Shep

+1

@Shep'count()'被评估* first *,其余代码永远不会达到,所以可以说 –

0

我发现

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中的一个错误,但看起来似乎不太可能,因为它有多标准。