itertools.ifilter与filter和列表推导式的对比

33 投票
4 回答
25709 浏览
提问于 2025-04-17 11:00

我正在努力熟悉一下 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]

4 个回答

5

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

生成器会在需要的时候动态生成它们的内容,而不是一开始就把整个列表都准备好。这就是 ifilterfilter 之间唯一的区别。

24

你的理解是正确的:唯一的区别在于 ifilter 返回的是一个迭代器,而使用 filter 就像是调用了:

list(ifilter(...))

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

列表推导式大大减少了对 filter()map() 的需求。同样,生成器表达式也被认为会减少对 itertools.ifilter()itertools.imap() 的需求。[...]

另外要注意的是,ifilter 在 Python 3 中变成了 filter(因此从 itertools 中移除了)。

17

下面的例子包含了一个数字生成器,它在输出数字之前会先打印一条消息。这个例子展示了 filter() 是先生成一个完整的列表,然后再对这个列表进行筛选。而 itertools.ifilter 则是在生成的过程中就进行筛选,根本不需要生成一个完整的列表。如果你要筛选50万个重要的东西,使用 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:
yield 0
yield 1
1
yield 2
2
stopping

filter:
yield 0
yield 1
yield 2
stopping
1
2

撰写回答