有人可以帮助我理解为什么实现"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).
这里有两个部分发挥作用:
在python-3.x中,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的信用)是一个实际上可以绑定i
在你的lambda中.您可以通过创建"高阶lambda"来完成此操作.而不是写:
lambda x : x == i or x % i != 0
你写:
(lambda j : (lambda x : x == j or x % j != 0))(i)
会发生什么是定义一个函数,该函数将j
实际取值的输入作为输入i
.通过立即调用它,j
绑定到的值i
.
在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
到你的lambda:
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]
或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)