Python の組み込み関数 filter の使い方です。
filter 関数で、iterable なオブジェクトから(リストやジェネレーターなどの反復可能なオブジェクトから)、不要な要素を除外します。
そのコード例と、実行結果を載せました。
あと、『エラーになったコード例』も書きました。
エラーになったコード例
filter 関数で、エラーになったコード例です。
(Python) filter(function, iterable)
filter()
TypeError: filter expected 2 arguments, got 0
filter(None)
TypeError: filter expected 2 arguments, got 1
filter(None, None)
TypeError: 'NoneType' object is not iterable
filter(None, 100)
TypeError: 'int' object is not iterable
filter(function=None, iterable=[1, 2, 3])
TypeError: filter() takes no keyword arguments
datas = filter(True, [1, 2, 3])
print(list(datas)) # TypeError
TypeError: 'bool' object is not callable
datas = filter('abc', [1, 2, 3])
print(list(datas)) # TypeError
TypeError: 'str' object is not callable
filter 関数の戻り値は『イテレーター』でした
filter 関数の戻り値は、リストではなくて、『filter オブジェクト』という名前の iterator になっていました。
(Python) filter(function, iterable)
(Python) リストからビューおよびイテレータへ(filter 関数はイテレータを返します)
(Python) iterable イテラブル(反復可能オブジェクト)
(Python) iterator イテレーター(データの流れを表現するオブジェクト)
filter(lambda x: x >= 2, [1, 2, 3])
<filter object at 0x0000000000000000>
なので、filter 関数から『結果を取り出すとき』は、戻り値を『tuple 関数 や list 関数』に渡したり、『next 関数や for 文』に渡したらできました。
datas = filter(lambda x: x >= 2, [1, 2, 3])
print(tuple(datas))
(2, 3)
(Python) class list([iterable])
datas = filter(lambda x: x >= 2, [1, 2, 3])
print(list(datas))
[2, 3]
(Python) next(iterator[, default])
datas = filter(lambda x: x >= 2, [1, 2, 3])
print(next(datas))
print(next(datas))
2
3
datas = filter(lambda x: x >= 2, [1, 2, 3])
for data in datas:
print(data)
2
3
tuple を渡した結果
filter 関数に、tuple を渡した結果です。
(Python) filter(function, iterable)
(Python) functools.partial(func, /, *args, **keywords)
(Python) operator.is_not(a, b)
(Python) isinstance(object, classinfo)
datas = filter(None, ())
print(tuple(datas))
()
datas = filter(None, (0, None, 5, 'abc'))
print(tuple(datas))
(5, 'abc')
from functools import partial
from operator import is_
# is_(None, 0), is_(None, None), is_(None, 5), ...
datas = filter(partial(is_, None), (0, None, 5, 'abc'))
print(tuple(datas))
(None,)
from functools import partial
from operator import is_not
# is_not(None, 0), is_not(None, None), is_not(None, 5), ...
datas = filter(partial(is_not, None), (0, None, 5, 'abc'))
print(tuple(datas))
(0, 5, 'abc')
datas = filter(lambda x: x is not None, (0, None, 5, 'abc'))
print(tuple(datas))
(0, 5, 'abc')
datas = filter(lambda x: isinstance(x, str), (0, None, 5, 'abc'))
print(tuple(datas))
('abc',)
list を渡した結果
filter 関数に、list を渡した結果です。
(Python) filter(function, iterable)
(Python) class list([iterable])
(Python) functools.partial(func, /, *args, **keywords)
(Python) operator.is_not(a, b)
(Python) isinstance(object, classinfo)
datas = filter(None, [])
print(list(datas))
[]
datas = filter(None, [0, None, 5, 'abc'])
print(list(datas))
[5, 'abc']
from functools import partial
from operator import is_
# is_(None, 0), is_(None, None), is_(None, 5), ...
datas = filter(partial(is_, None), [0, None, 5, 'abc'])
print(list(datas))
[None]
from functools import partial
from operator import is_not
# is_not(None, 0), is_not(None, None), is_not(None, 5), ...
datas = filter(partial(is_not, None), [0, None, 5, 'abc'])
print(list(datas))
[0, 5, 'abc']
datas = filter(lambda x: x is not None, [0, None, 5, 'abc'])
print(list(datas))
[0, 5, 'abc']
datas = filter(lambda x: isinstance(x, str), [0, None, 5, 'abc'])
print(list(datas))
['abc']
generator オブジェクトを渡した結果
filter 関数に、generator オブジェクトを渡した結果です。
(Python) filter(function, iterable)
(Python) ジェネレータ式(Python チュートリアル)
(Python) ジェネレータ式とリスト内包表記(Python 言語リファレンス)
(Python) ジェネレータ式 (generator expression)(Python 言語リファレンス)
(Python) ジェネレータ (generator)(Python チュートリアル)
src_datas = (x for x in [-10, -5, 0, 5, 10])
print(src_datas)
datas = filter(None, src_datas)
print(list(datas))
<generator object <genexpr> at 0x0000000000000000>
[-10, -5, 5, 10]
src_datas = (x for x in [-10, -5, 0, 5, 10])
print(src_datas)
datas = filter(lambda x: x >= 0, src_datas)
print(list(datas))
<generator object <genexpr> at 0x0000000000000000>
[0, 5, 10]
def generate_datas():
for x in [-10, -5, 0, 5, 10]:
yield x
print(generate_datas)
src_datas = generate_datas()
print(src_datas)
datas = filter(lambda x: x >= 0, src_datas)
print(list(datas))
<function generate_datas at 0x0000000000000000>
<generator object generate_datas at 0x0000000000000000>
[0, 5, 10]
iterator オブジェクトを渡した結果
filter 関数に、iterator オブジェクトを渡した結果です。
(Python) filter(function, iterable)
(Python) iter(object[, sentinel])
(Python) イテレータ (iterator)(Python チュートリアル)
(Python) イテレータ (iterator)(関数型プログラミング HOWTO)
src_datas = iter([-10, -5, 0, 5, 10])
print(src_datas)
datas = filter(None, src_datas)
print(list(datas))
<list_iterator object at 0x0000000000000000>
[-10, -5, 5, 10]
src_datas = iter([-10, -5, 0, 5, 10])
print(src_datas)
datas = filter(lambda x: x >= 0, src_datas)
print(list(datas))
<list_iterator object at 0x0000000000000000>
[0, 5, 10]
複数の条件を設定した結果
filter 関数に『複数の条件』を指定した結果です。
複数の条件は、自作関数で実現することができました。
自作関数は、『lambda 式』でも、普通の『関数定義』で作ったものでも、渡すことができました。
また、条件を分割して『filter 関数を繰り返し適用する方法』でも、同じ結果を得ることができました。
(Python) filter(function, iterable)
(Python) ラムダ式(Python チュートリアル)
(Python) ラムダ (lambda)(Python 言語リファレンス)
(Python) 関数を定義する(Python チュートリアル)
(Python) 関数定義(Python 言語リファレンス)
(Python) isinstance(object, classinfo)
試しに、x[0] が『文字列 (str)』で、x[1] が『None ではないもの』を選んでみました。
src_datas = [['abc', True], ['xyz', None], [None, True]]
func = lambda x: isinstance(x[0], str) and (x[1] is not None)
datas = filter(func, src_datas)
print(list(datas))
[['abc', True]]
src_datas = [['abc', True], ['xyz', None], [None, True]]
def func(x):
if isinstance(x[0], str):
if x[1] is not None:
return True
return False
datas = filter(func, src_datas)
print(list(datas))
[['abc', True]]
条件を分割して『filter 関数を繰り返し適用する方法』でもできました。
src_datas = [['abc', True], ['xyz', None], [None, True]]
temp_datas = filter(lambda x: isinstance(x[0], str), src_datas)
# list(temp_datas): [['abc', True], ['xyz', None]]
datas = filter(lambda x: x[1] is not None, temp_datas)
print(list(datas))
[['abc', True]]
『filter 関数』と『内包表記』は、どちらが良いのか?
自分は、『内包表記』のほうが、簡単で分かりやすくて良かったです。
filter 関数と同じような処理は、『リスト内包表記 []
』や『ジェネレータ式 ()
』で書くことができました。
(Python) 組み込み関数 (built-in function) のところにも、『Python のビルトイン関数 map() と filter() は、機能がジェネレータ式と重複しています』という説明がありました。
結果をリストで受け取るなら『角カッコのリスト内包表記 []
』が便利でしたし、遅延評価にするなら『丸カッコのジェネレータ式 ()
』が便利でした。
(Python) ジェネレータ式とリスト内包表記(Python 言語リファレンス)
(Python) ジェネレータ式 (generator expression)(Python 言語リファレンス)
(Python) generator expression(ジェネレータ式)(用語集)
(Python) list comprehension(リスト内包表記)(用語集)
内包表記などは、filter 関数とちがって、『lambda 式なし(自作関数なし)』で判定することができましたし、for 文も見えていて直感的でした。
さらに、リストのリストであっても、lambda 式を使うことなく、リストの要素を参照することができて、便利でした。
そういうわけで、filter 関数の使用は、機会があるたびに検討はしたものの、結局、内包表記やジェネレータ式を使うに至りました。
filter 関数よりも、内包表記などのほうが、機能的にも使いやすさ的にも、メリットが大きかったです。
実行速度の比較についてです。
Python マニュアルの『プログラミング FAQ』の中で、少しだけ言及がありました。
リストからアイテムを除去するコード例のところで、『filter 関数』と『ジェネレータ式』と『リスト内包表記』の速度について、触れていました。
(Python) How do you remove multiple items from a list (The list comprehension may be fastest.)
以上です。