Python 2 与 Python 3 - 过滤器行为的差异 [英] Python 2 vs Python 3 - Difference in behavior of filter

查看:29
本文介绍了Python 2 与 Python 3 - 过滤器行为的差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人可以帮助我理解为什么以下实现埃拉托色尼筛"的代码在 Python 2 和 Python 3 中表现不同.

l = range(2, 20)对于范围内的 i (2, 6):l = filter(lambda x: x == i or x % i != 0, l)打印(元组(l))

使用 Python 2.7:

<代码>>蟒蛇过滤器.py(2, 3, 5, 7, 11, 13, 17, 19)

使用 Python 3.6:

<代码>>蟒蛇过滤器.py(2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19)

我了解Python3的过滤器返回一个过滤器对象但无法解释最终结果.(代码来自这个 lambdas 教程 1).

解决方案

有两个部分在这里起作用:

  • , filter 作为生成器工作:过滤是惰性的;和
  • lambda x : ... 中的 ifor 中的 i 被更新> 循环进行.

所以最后你构建的东西是这样的:

l = filter(lambda x: x == 5 or x % 5 != 0,filter(lambda x: x == 5 或 x % 5 != 0,filter(lambda x: x == 5 或 x % 5 != 0,过滤器(lambda x: x == 5 或 x % 5 != 0,l))))

请注意,所有过滤都像 i 一直是 5 一样.所以现在你调用tuple(..),实际的过滤就完成了,正如你所看到的,只有不是五个本身的五个的倍数被过滤掉了.

一个简单的解决方法是在循环中使用 list 以便 filter 主动完成:

l = range(2, 20)对于范围内的 i (2, 6):l = list(filter(lambda x: x == i or x % i != 0, l))打印(元组(l))

在 python 中运行它返回:

<预><代码>>>>l = 范围(2, 20)>>>对于范围内的 i (2, 6):... l = list(filter(lambda x: x == i or x % i != 0, l))...>>>打印(升)[2, 3, 5, 7, 11, 13, 17, 19]

请注意,虽然 看起来完全一样,这些实际上是彼此不兼容的不同"语言:运行用一种编写的代码并不总是适用于另一种,反之亦然.

另一个说明(归功于@ShadowRanger)是实际上可以在您的 lambda 中绑定 i.您可以通过创建一个高阶 lambda"来做到这一点.而不是写:

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

你写:

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

所发生的事情是您定义了一个函数,该函数将 j 作为输入,而该函数实际上采用 i 的值.通过立即调用它,j 绑定到 i 的值.

Could someone please help me understand why the following code that implements the "sieve of Eratosthenes" behaves differently across Python 2 and 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))

With Python 2.7:

> python filter.py
(2, 3, 5, 7, 11, 13, 17, 19)

with Python 3.6:

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

I understand that Python3's filter returns a filter object but can't explain the final result. (The code is from this lambdas tutorial 1).

解决方案

There are two parts that play a role here:

  • in , filter works as a generator: the filtering is done lazy; and
  • the i in the lambda x : ... is updated as well as the i in the for loop makes progression.

So at the end what you have constructed is something like:

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)
            )
        )
    )

Note that all filtering is done as if i was 5 all the time. So now you call tuple(..), the actual filtering will be done, and as you can see only multiples of five that are not five themeselves are filtered out.

An easy fix is to use list in the loop such that the filtering is done actively:

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))

Running this in python returns:

>>> 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]

Mind that although and look quite the same these are actually "different" languages that are incompatible with each other: running code written in one will not always work in the other and vice versa.

Another note (credits to @ShadowRanger) is that one actually can bind i in your lambda. You do this by creating a "higher order lambda". Instead of writing:

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

you write:

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

What happens is you define a function that takes as input a j that actually takes the value of i. By calling it immediately, j binds to the value of i.

这篇关于Python 2 与 Python 3 - 过滤器行为的差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆