首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python 2与Python 3-过滤器行为的差异

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

Stack Overflow用户
提问于 2017-01-15 22:23:05
回答 2查看 9.5K关注 0票数 16

有谁能帮我理解一下为什么下面的代码在Python 2和Python 3之间实现“Eratosthenes的筛子”的行为有所不同。

代码语言:javascript
复制
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:

代码语言:javascript
复制
> python filter.py
(2, 3, 5, 7, 11, 13, 17, 19)

使用Python3.6:

代码语言:javascript
复制
> python filter.py
(2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19)

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-01-15 22:31:50

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

  • python-3.x中,filter充当生成器:过滤是延迟完成的;
  • i更新了lambda x : ...中的ifor循环中的i也进行了升级。

所以在最后,你所构建的是这样的:

代码语言:javascript
复制
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了:

代码语言:javascript
复制
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中运行此操作将返回:

代码语言:javascript
复制
>>> 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.7python-3.x看起来完全相同,但实际上它们是“不同的”语言,互不兼容:用一种语言编写的代码并不总是在另一种语言中运行,反之亦然。

另一个注意事项(@ShadowRanger的学分)是,一个实际上可以在您的lambda中绑定。您可以通过创建“高阶lambda”来做到这一点。而不是写:

代码语言:javascript
复制
lambda x : x == i or x % i != 0

你写:

代码语言:javascript
复制
(lambda j : (lambda x : x == j or x % j != 0))(i)

所发生的事情是定义一个函数,它以一个j作为输入,它实际上接受i的值。通过立即调用它,j绑定到i的值。

票数 13
EN

Stack Overflow用户

发布于 2017-01-15 22:34:12

在Python-3中,filter返回一个生成器(在Python-2中它返回一个列表),所以在使用它时会对它进行评估。但这本身并不是一个问题,问题是您的i发生了变化。在使用filteri = 5和所有filter时,只需检查一下。

我包括一些print-statements,这样您就可以更容易地跟踪正在发生的事情:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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-result立即转换为tuple

代码语言:javascript
复制
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)
票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41666977

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档