itertools.ifilter与filter和列表推导式的对比
我正在努力熟悉一下 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
返回的是一个生成器,而不是一个列表。
生成器会在需要的时候动态生成它们的内容,而不是一开始就把整个列表都准备好。这就是 ifilter
和 filter
之间唯一的区别。
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