为了了解lambdas,我遵循了这个教程,并运行了这个关于计算素数的例子(python2.x):
nums = range(2,50)
for i in range(2,8):
nums = filter(lambda x: x == i or x % i, nums)
print (list(nums))版画
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]但是,在python 3.4中尝试此操作时,它会产生意想不到的行为:
nums = range(2,50)
for i in range(2,8):
nums = filter(lambda x: x == i or x % i , nums)
print(list(nums))版画
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 41, 43, 44, 45, 46, 47, 48]我不明白为什么会有区别。我知道filter在python 3中返回一个filter对象(而不是一个列表),但据我所知,这不会影响结果。
删除for循环会产生正确的结果:
>>> nums = range(2,50)
>>> nums = filter(lambda x: x == 2 or x % 2, nums)
>>> nums = filter(lambda x: x == 3 or x % 3, nums)
>>> nums = filter(lambda x: x == 4 or x % 4, nums)
>>> nums = filter(lambda x: x == 5 or x % 5, nums)
>>> nums = filter(lambda x: x == 6 or x % 6, nums)
>>> nums = filter(lambda x: x == 7 or x % 7, nums)
>>> print(list(nums))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]我希望有人能启发我,因为我对正在发生的事情感到好奇。
发布于 2016-01-17 20:29:43
这种行为是由两件事结合而成的。一种是,在Python3中,filter (和range)返回每次生成一个值的对象,而不是预先计算所有值。另一个是,在Python2和3中,在封闭作用域中引用名称的函数在名称,而不是值上创建闭包。
在Python 3版本中,在每个循环迭代中,使用一个函数( lambda)创建一个过滤器。因为过滤器是“懒惰”的,所以它存储函数,然后在您请求筛选值时调用它。(在这种情况下,您可以调用list(nums)。)但是,该函数引用变量i,它位于函数之外。因此,当filter调用函数时,它使用在获得筛选值(即调用list(nums))时存在的i值来调用它,而不是在创建过滤器时。这就是为什么您的结果丢失了7的所有倍数(7除外):7是i循环中的最后一个值,所以所有的lambda在调用时都在检查7的倍数。
如Bhargav在一条评论中所说,复制Python2行为的一种方法是将lambda更改为筛选list(nums),而不是nums。这迫使每个过滤器“清除”前一个过滤器,而不是等待在最后应用它们。(这实际上就是Python 2所做的,这就是为什么在Python 2中看不到这种行为的原因。)
另一种方法是使用关于闭包的链接问题中描述的默认参数技巧。将循环体更改为:
nums = filter(lambda x, i=i: x == i or x % i , list(nums))使i成为lambda在每个循环迭代中“锁定”值的参数。这意味着过滤器仍将惰性地运行,但每个过滤器都将存储要筛选的适当值,因此即使您稍后调用它(在更改i之后),它仍然可以工作。
https://stackoverflow.com/questions/34843139
复制相似问题