10

Python (3.3) でフィルター関数を使用しています。フィルタ オブジェクトをリストに変換しようとしました。それが私が見つけたものです:

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

それは私にはかなり奇妙です。誰でもこれを説明できますか?

4

1 に答える 1

12

Python 3 では、イテレータ型filter()を返し、すべてのイテレータと同様に、1 回だけ反復できます。イテレータは必要に応じて値をフィルタリングします。メモリ自体にはフィルタリングされた値は保持されません。filter()

によって返されるリスト反復子でも同じことができますiter()

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

これは、反復子の.__next__()メソッドStopIterationが使い果たされると発生すると予想され、その後は常に発生しなければならないためStopIterationに発生します。

イテレータの__next__()メソッドが を発生させる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__()はiterator メソッドを呼び出し、発生した例外を伝播します。list()一方、 まで繰り返しStopIteration、その例外をキャッチし、なんとか受け取った要素のリストを返します。

完全を期すために、Python 2 ではfilter()(他の多くの組み込み関数やメソッドと同様に) を返しますlist。これは、反復後に再び破棄される中間リスト オブジェクトを構築する際にメモリとサイクルを浪費することがよくあります。代わりにイテレータを返すことで、リストを実体化するかどうかの選択はプログラマ次第です。

于 2013-11-03T22:59:18.523 に答える