概要
Pythonのfilter
関数で、以下のケースではどのような結果になるのだろう?と思ったので実施してみました。
- 第一引数(
function
)にNone
を指定した場合 - 第一引数(
function
)が常にTrue
を返す場合 - 第一引数(
function
)が常にFalse
を返す場合
サンプルコード
def is_even(n):
return n % 2 == 0
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even_numbers = list(filter(is_even, numbers))
print(even_numbers)
# 出力結果: [2, 4, 6, 8, 10]
filter()
関数は、第一引数に指定した関数(条件)に合致する要素を残します。
なので、上記の場合、偶数の要素のみが出力されます。
第一引数に指定したものでフィルターしてくれる、というわけです。
しかし、この考えだと少し違うことがわかりました。
正確にいうと、is_even()
関数が真を返す要素(偶数)だけが残る、ということです。
第一引数(function
)にNone
を指定した場合は?
次に以下のコードを見てみます。
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, None]
even_numbers = list(filter(None, numbers))
print(even_numbers)
0
とNone
を追加しました。
フィルターされるんだ、という考えだとNone
(と0
)だけが残る、となりそうですが、そうではありません。
結果は以下になります。
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
これは上述の通り、正確には第一引数に渡されたものがbool()
として評価され、True
を返す要素がフィルタリングされるからです。
第一引数にNone
が入った場合、bool(None)
でFalse
と評価されるため、None
以外の要素が残るのです。
filter
の基本構文は以下の通り。
filter(function, iterable)
-
function
: フィルタリング条件を定義する関数。この関数は、引数としてイテラブルの要素を受け取り、それを条件として評価して真偽値(True
またはFalse
)を返します。 -
iterable
: フィルタリングされる対象のイテラブルオブジェクト。
また、以下のように説明があります。
class filter(object)
| filter(function or None, iterable) --> filter object
|
| Return an iterator yielding those items of iterable for which function(item)
| is true. If function is None, return the items that are true.
return the items that are true
とある通り、None
を指定した場合、filter()
はイテラブルの各要素を真偽値として評価し、True
となる要素のみをフィルタリングします。つまり、
None
を指定する
↓
「function
無し」という意味
↓
function
がない時は、イテラブルの各要素を真偽値として評価して、True
となる要素のみを残すよ〜
というのがfilter
関数なのです。
一般的な関数とはちょっと違う関数ですよね。
第一引数(function
)が常にTrue
を返す場合は?
以下の場合を見てみます。
def is_not_function(x):
return "これは抽出条件とは言えません!"
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, None]
filtered_data = list(filter(is_not_function, numbers))
print(filtered_data)
# 結果
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, None]
print(bool(is_not_function))
# 結果
# True
上記コードでは、抽出条件としてふさわしくない関数(=何でも通してしまう関数)を第一引数にしています。この場合、この関数の結果は常にTrue
になってしまうので、何もフィルターしてくれないことになります。None
や0
も含めてすべて出力されます。
役立たずの関数、といったイメージですね...
第一引数(function
)が常にFalse
を返す場合は?
def is_not_function(x):
return None
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, None]
filtered_data = list(filter(is_not_function, numbers))
print(filtered_data)
# 結果
# []
print(is_not_function("test"))
print(bool(is_not_function("test")))
# 結果
# None
# False
この場合、関数自体が常にNone
を返すので、条件判定が常にFalse
となります。
各要素に適用したところで全てNone
を返すので、全ての要素が条件を満たさないと見なされ、フィルタリングされた結果、空のリスト[]
が返されたのです。None
や0
も含め、何も出力されません。
こちらは全拒否の関数、といったイメージですね...
None
だけをフィルターしたい時は?
どうしてもfilter
関数でNone
がほしい!という時は、以下のように関数を作成してその結果に等しいものだけを抽出するようにしてあげると実現できます。
def is_none(x):
return x is None
data = [1, None, 3, None, 5, None]
filtered_data = list(filter(is_none, data))
print(filtered_data) # 出力結果: [None, None, None]
ちなみに、0
や空文字列、False
、None
が偽と見なされます。
補足:戻り値はイテレータ!
戻り値はイテレータとなります。
なので抽出した要素を扱うには、上述のコードのようにlist
関数でリストに変換するなどの処理を行います。list
にしない場合どのような結果になるのでしょうか。例えば、以下のようにしてプリントします。
def is_even(n):
return n % 2 == 0
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, None]
even_numbers = filter(is_even, numbers)
print(even_numbers) # 出力結果: [2, 4, 6, 8, 10]
すると出力結果は以下になります。
<filter object at 0xffff7f536160>
単なるイテレータであるfilter
オブジェクトであることが確認できました。
比較サンプル
以下、None
を指定した場合とそうでない場合のコード比較です。
data_normal = {"sample_code":["01", "02", "03"]}
data_normal_list = list(filter(None, data_normal.get("sample_code", [])))
data_normal_list2 = data_normal.get('sample_code', [])
print(data_normal_list)
print(data_normal_list2)
# 結果
# ['01', '02', '03']
# ['01', '02', '03']
data_blank = {"sample_code":[]}
data_blank_list = list(filter(None, data_blank.get("sample_code", [])))
data_blank_list2 = data_blank.get('sample_code', [])
print(data_blank_list)
print(data_blank_list2)
# 結果
# []
# []
data_empty = {"sample_code":['']}
data_empty_list = list(filter(None, data_empty.get("sample_code", [])))
data_empty_list2 = data_empty.get('sample_code', [])
print(data_empty_list)
print(data_empty_list2)
# 結果
# []
# ['']
data_none= {"sample_code":[None]}
data_none_list = list(filter(None, data_none.get("sample_code", [])))
data_none_list2 = data_none.get('sample_code', [])
print(data_none_list)
print(data_none_list2)
# 結果
# []
# [None]
ちなみに、紹介していたコードではget
メソッドのデフォルト値で空のリストを指定しています。
以下の場合、"sample_code"
キーが存在しない場合、デフォルト値の「ありません!
」を返します。あくまでキーが存在しない場合のデフォルト値であり、キーの値がNone
でもFalse
でも存在していればデフォルト値にはなりません。
data_no_sample = {}
data_no_sample_list = list(filter(None, data_no_sample.get("sample_code", ['ありません!'])))
data_no_sample_list2 = data_no_sample.get('sample_code', ['ありません!'])
print(data_no_sample_list)
print(data_no_sample_list2)