10

我在 Python (3.3) 中使用 filter 函数。我试图将过滤器对象转换为列表。这就是我发现的:

>>> a=['1', '2', '3', None]
>>> b=filter(None,a)
>>> list(b)
['1', '2', '3']
>>> list(b)
[]

这对我来说很奇怪。谁能解释一下?

4

1 回答 1

12

在 Python 3 中,filter()返回一个迭代器类型,并且像所有迭代器一样,只能迭代一次。迭代器filter()按需过滤值,它在内存中不保存任何过滤值。

您可以对列表迭代器执行相同的操作,返回iter()

>>> a = [1, 2, 3]
>>> b = iter(a)
>>> list(b)
[1, 2, 3]
>>> list(b)
[]

发生这种情况是因为迭代器的.__next__()方法预计会StopIteration在耗尽后引发,然后必须始终StopIteration从那里引发:

一旦迭代器的__next__()方法 raise StopIteration,它必须在后续调用中继续这样做。不遵守此属性的实现被视为已损坏。

filter()这样做正确:

>>> a = [1, 2, 3, None]
>>> b = filter(None, a)
>>> list(b)
[1, 2, 3]
>>> next(b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

这里next()函数调用.__next__()迭代器方法,并传播引发的异常;list()另一方面,迭代 until StopIteration,捕获该异常并返回它设法接收的任何元素的列表。

为了完整起见,在 Python 2 中,filter()(以及许多其他内置函数和方法)返回 a list,通常会浪费内存和循环来构建中间列表对象,然后在迭代后再次丢弃该对象。通过返回一个迭代器,实现列表的选择由程序员决定。

于 2013-11-03T22:59:18.523 回答