2017-08-09 17 views
1

は以下がitertools.productは引数を遅延評価しますか?

のPython 3.6で
from itertools import product, count 

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

を何かを印刷したことがない代わりに、それはただそこに座って、CPUを燃やします。問題は、productが最初に完全であると評価されるため、無限の領域を超えている場合には、反復子を返さないということです。 productがジェネレータであると仮定すると、これは驚くべきことです。

私は、(無限に)カウントアップを開始するには、この発電機(directly from the docsをとら)の行動のようなもの、これを期待しているでしょう:

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

をしかし、私の発電機がproductを使用して1、すぐにカウント決して開始していないのに対し、まったくカウントする。

他のツール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 implementationで、poolsはタプルのタプルです:引数はイテレータトンとして残された場合productは時々不可能な、何度も反復可能な多くのを越える必要があるため

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; 
} 

これがそうです帽子は一度しか消費できません。

実質的には、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()'が最初に評価され、コードの残りの部分に到達することはありません。つまり、 –

0

私は

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

は何Iないことがわかりました期待する。これはそれがis listed as equivelent in the docsであることを考えると奇妙です。これはitertools.productのバグのようですが、どのように標準であるかはわかりません。