2015-10-17 2 views
6

[パイソン3.4]シンプルエラトステネス篩で以下のプログラム:Pythonジェネレータ。 2つの明らかに同一のプログラムが異なる動作

from itertools import * 
def excl(ns,pr): 
    return (i for i in ns if i%pr) 
def sieve(ns): 
    while True: 
     pr=next(ns) 
     yield pr 
     ns=excl(ns,pr) 
     # ns=(i for i in ns if i%pr) 
r=list(islice(sieve(count(2)),10)) 

[2、3、5、7、11、13、17、19、23、29を生成します]。 OK。 excl()をインライン化し、呼び出しをコメントする行のコメントを外して、[2,3,4,5,6,7,8,9,10,11]とします。どうして?

ループを反復するループ内でシーケンスを変更するときに問題が発生することはありますか?

ありがとうございます。

答えて

2

あなたの問題は、ジェネレータ式で参照されるprはあなたのwhileループの次の反復でを変更することpr同じで、前回の「プライム」の数で割り切れないので、すべての数が扱われていることです「プライム」として。 prなどを変更するものです。excl関数では、参照するprが引数として渡されますが、決して変更されません。

+0

私はこの回答を理解しているかどうかはわかりません。素数はexcl(gen.expression)では変更されず、ループ内で変更され、このコンテキストはインライン化された 'call'バージョンと同じです。私はfilter()について間違った発言を削除しました。 –

+0

@JerzyKarczmarczuk [PEP 227](https://www.python.org/dev/peps/pep-0227/)によれば、名前がコードブロック(ネストされた関数)内で使用されていてもそこにバインドされていないグローバルに宣言されていない場合は、**最も近い包囲関数領域への参照として扱われます。あなたのケースに当てはまるように、ジェネレータ式はフードの下の関数であり、変数 'pr'を定義しないので、' pr'は囲み関数の 'pr'の**参照**です'ふるい ')。つまり、 'sieve 'の' pr'が変更されると、ジェネレータ表現の 'pr'も変わります。 – ppperry

関連する問題