有人可以帮助我理解为什么以下代码实现了Eratosthenes"筛选Eratosthenes"在Python 2和Python 3中表现不同。
l = range(2, 20)
for i in range(2, 6):
l = filter(lambda x: x == i or x % i != 0, l)
print(tuple(l))
使用Python 2.7:
> python filter.py
(2, 3, 5, 7, 11, 13, 17, 19)
使用Python 3.6:
> python filter.py
(2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19)
我知道Python3的过滤器会返回一个过滤器对象但无法解释最终结果。 (代码来自这个lambdas教程1)。
答案 0 :(得分:7)
在Python-3 filter
中返回一个生成器(在Python-2中它返回一个列表),因此在你使用它时会对它进行评估。但这本身并不是一个问题,问题是你的i
会发生变化。当您使用filter
i = 5
filter
以及所有print
时,只需检查一下。
我添加了一些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]
绑定到你的lambda:
filter
或立即将tuple
- 结果投射到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)
:
{{1}}
答案 1 :(得分:5)
这里有两个部分发挥作用:
filter
作为生成器:过滤是懒惰的;和i
中的lambda x : ...
已更新,i
循环中的for
也会更新。所以你最终构建的是:
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)
)
)
)
请注意,所有过滤都是i
始终为5
。所以现在你打电话给tuple(..)
,实际过滤就会完成,而且你可以看到只有五个不是五个自身的多个被过滤掉了。
一个简单的解决方法是在循环中使用list
,以便filter
积极完成:
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中运行它返回:
>>> 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]
请注意,虽然python-2.7和python-3.x看起来完全相同,但实际上这些"不同"彼此不兼容的语言:运行在一个语言中的代码并不总是在另一个语言中起作用,反之亦然。
另一个注释(归功于@ShadowRanger)是一个实际上可以绑定你的lambda中的i
。你通过创建一个更高阶的lambda"来做到这一点。而不是写:
lambda x : x == i or x % i != 0
你写道:
(lambda j : (lambda x : x == j or x % j != 0))(i)
您定义了一个函数,该函数将实际取值为j
的{{1}}作为输入。通过立即调用它,i
会绑定j
的值。