LoginSignup
0
1

【Python】filter関数で第一引数に None / 常にTrueを返す関数 /常にFalseを返す関数 を指定してみる

Posted at

概要

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)

0Noneを追加しました。
フィルターされるんだ、という考えだと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になってしまうので、何もフィルターしてくれないことになります。None0も含めてすべて出力されます。

役立たずの関数、といったイメージですね...

第一引数(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を返すので、全ての要素が条件を満たさないと見なされ、フィルタリングされた結果、空のリスト[]が返されたのです。None0も含め、何も出力されません。

こちらは全拒否の関数、といったイメージですね...

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や空文字列、FalseNoneが偽と見なされます。

補足:戻り値はイテレータ!

戻り値はイテレータとなります。
なので抽出した要素を扱うには、上述のコードのように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)
0
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1