itertools.ifilter 与 filter 与列表推导式的区别

32

我正在尝试熟悉 itertools 模块,并找到了一个名为 ifilter 的函数。

据我所知,它基于给定的函数对可迭代对象进行过滤,返回一个迭代器,该迭代器包含在函数评估为 True 的可迭代对象的元素。

问题1: 我目前的理解是否正确?

问题2: 除了返回迭代器之外,它与内置的 filter 函数有什么区别?

问题3 哪个更快?

根据我所看到的,它并不是更快的。我演示了以下测试,还有别的吗?

>>> itertools.ifilter(lambda x: x%2, range(5))
<itertools.ifilter object at 0x7fb1a101b210>
>>> for i in itertools.ifilter(lambda x: x%2, range(5)): print i
... 
1
3
>>> filter(lambda x: x%2, range(5))
[1, 3]
>>> function = lambda x: x%2
>>> [item for item in range(5) if function(item)]
[1,3]

你期望的输出是什么?range(5)会给你 [0,1,2,3,4] - istruble
1
请注意,大多数使用 filter 的情况都可以通过在生成器/列表表达式上使用 guard 来替换:list(x for x in range(5) if x%2) - Dan D.
1
请注意,3.x中不再存在itertools.ifilter,而filter会表现得懒惰。 - Karl Knechtel
4个回答

23
您的理解是正确的:唯一的区别在于,ifilter 返回一个迭代器,而使用 filter 就像调用:
list(ifilter(...))

您可能对 PEP 289 关于 filter 和 ifilter 的内容感兴趣:

列表推导式大大减少了使用 filter()map() 的需求。同样,生成器表达式也有望将使用 itertools.ifilter()itertools.imap() 的需求最小化。[...]

还请注意,在 Python-3 中,ifilter 已经变成了 filter(因此从 itertools 中移除)。


17

下面的示例包括一个数字生成器,它在生成数字之前立即打印一条消息,展示了filter()首先建立列表,然后运行并过滤该列表。而itertools.ifilter则是边过滤边生成,不会建立列表。如果你正在过滤500,000个重要的内容,你应该使用ifilter,这样就不需要建立列表。

import itertools

def number_generator():
    for i in range(0, 3):
        print "yield", i
        yield i
    print "stopping"

function = lambda x: x > 0

numbers = number_generator()
print "itertools.ifilter:"
for n in itertools.ifilter(function, numbers):
    print n

print "\nfilter:"
numbers = number_generator()
for n in filter(function, numbers):
    print n

输出:

itertools.ifilter:
产出0
产出1
1
产出2
2
停止
filter: 产出0 产出1 产出2 停止 1 2

5

ifilter 返回的是生成器,而不是列表。

生成器会在需要时动态生成其项目,而不是先分配整个列表。这是 ifilterfilter 之间唯一的区别。


1
生成器是迭代器,严格来说它返回一个itertools.ifilter对象。 - Rik Poggi

2
在这里,您可以看到区别: filter(function, iterable)从可迭代的元素中构造一个列表,其中函数返回true。 itertools.ifilter(predicate, iterable)创建一个iterator,该迭代器过滤掉 iterable 中仅返回 predicate 为 True 的元素。
这意味着要获取“ifiltered”项,您应该使用返回的迭代器进行迭代,但是“filter”会返回一个不需要迭代的列表中的所有元素。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接