2017-01-15 6 views
4

は、誰かが「エラトステネスのふるい」を実装し、次のコードは、PythonでのPython 2とPython 3のPython 2から

l = range(2, 20) 
for i in range(2, 6): 
    l = filter(lambda x: x == i or x % i != 0, l) 
print(tuple(l)) 

渡って異なった動作を、なぜ私が理解するのに役立つてもらえフィルタの挙動の違い2.7:

は、Python 3.6と
> python filter.py 
(2, 3, 5, 7, 11, 13, 17, 19) 

> python filter.py 
(2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19) 

私は理解のpython3のことfilterはフィルタオブジェクトを返しますが、最終結果を説明することはできません。 (コードはこのラムダチュートリアル1のものです)。

+4

フィルタが発電機として動作 '、Pythonの-3.xではので。 –

+2

@WillemVanOnsemあなたは完全な答えを書く必要があります。この種の質問はそれに値する。 – Soviut

+2

@ソヴィエット:私はそれに取り組んでいます。 –

答えて

3

がここに役割を果たしている二つの部分があります。

  • では、発電機としてfilter作品:フィルタリングが怠惰に行われます。
  • lambda x : ...iが更新され、forループの進行が更新されます。

だから、最後に、あなたが構築してきたことのようなものです:i5すべての時間たかのようにすべてのフィルタリングが行われていることを

l = filter(lambda x: x == 5 or x % 5 != 0, 
     filter(lambda x: x == 5 or x % 5 != 0, 
      filter(lambda x: x == 5 or x % 5 != 0, 
       filter(lambda x: x == 5 or x % 5 != 0,l) 
      ) 
     ) 
    ) 

注意。だからtuple(..)と呼ばれ、実際のフィルタリングが行われ、5つのテーマではない5つの倍数だけが除外されます。

簡単な修正はfilter INGが積極的に行われているようなループでlistを使用することです:もののおよび見えること

>>> l = range(2, 20) 
>>> for i in range(2, 6): 
...  l = list(filter(lambda x: x == i or x % i != 0, l)) 
... 
>>> print(l) 
[2, 3, 5, 7, 11, 13, 17, 19] 

マインド:

l = range(2, 20) 
for i in range(2, 6): 
    l = list(filter(lambda x: x == i or x % i != 0, l)) 
print(tuple(l)) 

はPythonの戻りでこれを実行しますこれらはまったく同じですが、実際には「異なる」言語であり、互いに互換性がありません。つまり、実行コードは常に別の言語で動作するとは限りません。

もう1つの注意(@ ShadowRangerのクレジット)は、実際にがあなたのラムダにiをバインドできるということです。これを行うには、「上位ラムダ」を作成します。代わりに、書き込みの:

lambda x : x == i or x % i != 0 

あなたが書いた:何が起こることはあり

(lambda j : (lambda x : x == j or x % j != 0))(i) 

あなたは、入力として取る関数を定義し、実際にiの値をとることj。すぐに呼び出すと、jiの値にバインドされます。

+1

'lambda'の' i'の値をバインドして中間リストなしで同じ結果を得ることができるので、各ループで更新されないようにすることができます: 'filter(lambda x、i = i:x == i or x%i!= 0、l) 'デフォルトパラメータi = iを設定すると、定義時間にバインドされるので、ループの進行によって変更されません。 – ShadowRanger

+0

@ShadowRanger:それは確かに良い点です。私はこれを含めるために私の答えを編集します。 –

+0

@ShadowRanger:何が起こるのかがはっきりしているので、高次関数を定義しました。それにもかかわらず、あなたのアプローチは同様に機能します。それはすべてローカルの 'i'を定義することと関係しています。 –

7

Python-3でfilterはジェネレータを返します(Python-2ではリストを返します)ので、消費時に評価されます。しかし、それだけでは問題ではないでしょう、問題はあなたのiが変更されていることです。当時、あなたはfilterあなたのi = 5を消費し、すべてあなたのfilterはそれをチェックするだけです。

あなたがより簡単に何が起こっているかを辿ることができますので、私はいくつか print -statementsが含ま

:おそらくあなたの意図はなかった

l = range(2, 20) 
for i in range(2, 6): 
    l = filter(lambda x: print(x, i) or (x == i or x % i != 0), l) 
list(l) 

2 5 
2 5 
2 5 
2 5 
3 5 
3 5 
3 5 
3 5 
4 5 
4 5 
4 5 
4 5 
5 5 
5 5 
5 5 
5 5 
6 5 
6 5 
6 5 
6 5 
7 5 
7 5 
7 5 
7 5 
8 5 
8 5 
8 5 
8 5 
9 5 
9 5 
9 5 
9 5 
10 5 
11 5 
11 5 
11 5 
11 5 
12 5 
12 5 
12 5 
12 5 
13 5 
13 5 
13 5 
13 5 
14 5 
14 5 
14 5 
14 5 
15 5 
16 5 
16 5 
16 5 
16 5 
17 5 
17 5 
17 5 
17 5 
18 5 
18 5 
18 5 
18 5 
19 5 
19 5 
19 5 
19 5 

[2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19] 

。あなたは、ラムダにiをバインドすることができます:

l = range(2, 20) 
for i in range(2, 6): 
    l = filter((lambda j: lambda x: print(x, j) or (x == j or x % j != 0))(i), l) 
    # or 
    # l = filter(lambda x, i=i: print(x, i) or (x == i or x % i != 0), l) 
list(l) 
2 2 
2 3 
2 4 
2 5 
3 2 
3 3 
3 4 
3 5 
4 2 
5 2 
5 3 
5 4 
5 5 
6 2 
7 2 
7 3 
7 4 
7 5 
8 2 
9 2 
9 3 
10 2 
11 2 
11 3 
11 4 
11 5 
12 2 
13 2 
13 3 
13 4 
13 5 
14 2 
15 2 
15 3 
16 2 
17 2 
17 3 
17 4 
17 5 
18 2 
19 2 
19 3 
19 4 
19 5 

[2, 3, 5, 7, 11, 13, 17, 19] 

またはすぐtupleにごfilter -resultをキャスト:

l = range(2, 20) 
for i in range(2, 6): 
    l = tuple(filter(lambda x: x == i or x % i != 0, l)) 
print(l) 
# (2, 3, 5, 7, 11, 13, 17, 19) 
関連する問題