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

# 概要
Pythonの`filter`関数で、以下のケースではどのような結果になるのだろう？と思ったので実施してみました。

- 第一引数(`function`)に`None`を指定した場合
- 第一引数(`function`)が常に`True`を返す場合
- 第一引数(`function`)が常に`False`を返す場合

## サンプルコード

```py
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`を指定した場合は？
次に以下のコードを見てみます。

```py
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`: フィルタリングされる対象のイテラブルオブジェクト。

また、以下のように説明があります。

```py

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`を返す場合は？
以下の場合を見てみます。

```py
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`を返す場合は？

```py
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`がほしい！という時は、以下のように関数を作成してその結果に等しいものだけを抽出するようにしてあげると実現できます。

```py
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`にしない場合どのような結果になるのでしょうか。例えば、以下のようにしてプリントします。

```py
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`を指定した場合とそうでない場合のコード比較です。

```py
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']
```

```py
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)

# 結果
# []
# []
```

```py
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)

# 結果
# []
# ['']
```

```py
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`でも存在していればデフォルト値にはなりません。

```py
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)
```