当前位置:  开发笔记 > 编程语言 > 正文

Python 2与Python 3 - 过滤器行为的差异

如何解决《Python2与Python3-过滤器行为的差异》经验,为你挑选了2个好方法。

有人可以帮助我理解为什么实现"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).



1> Willem Van O..:

这里有两个部分发挥作用:

在python-3.x中,filter作为一个生成器:过滤是懒惰的; 和

ilambda x : ...更新,以及在ifor环,使进展.

所以最后你所构建的是:

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

需要注意的是,就像所有过滤完成i5所有的时间.所以现在你打电话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.



2> MSeifert..:

在Python-3中filter返回一个生成器(在Python-2中它返回一个列表),因此在你使用它时会对它进行评估.但这本身不是问题,问题在于你的i改变.当你消费filteri = 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)

推荐阅读
oDavid_仔o_880
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有