0や空文字列を「値が無い」と誤判定してしまう
0、空文字列、空リストはすべてfalsyですが、「値が渡されていない」こととは意味が違います。if x: で済ませると、意図的に渡されたfalsyな値を見落とします。
なぜエラーが出ないのか
出力: 10
(エラーなし)- Pythonは何も報告しません。文法として正しいためです
出力: 10- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 def get_discount(discount=None): 2 if discount : ^ 3 return discount 4 return 10 5 6 print(get_discount(0))
0や空文字列、空リストは「値が無い」ことと「falsyな値」を混同しやすい典型例です。値が渡されたかどうかを調べたい場合はis not Noneを使います。
直し方: discount を discount is not None にします。
パターン2
1 def get_username(name=None): 2 if name : ^ 3 return name 4 return "guest" 5 6 print(repr(get_username("")))
空文字列は「値が渡された」ことに変わりありません。「値が無い」かどうかの判定にはis not Noneを使い、値そのものの真偽値と混同しないようにします。
直し方: name を name is not None にします。
パターン3
1 def get_tags(tags=None): 2 if tags : ^ 3 return tags 4 return ["default"] 5 6 print(get_tags([]))
空リストを意図的に渡した場合でも「値が無い」と誤判定されます。呼び出し側が空リストを渡した意図まで尊重するには、Noneかどうかだけを見る必要があります。
直し方: tags を tags is not None にします。
パターン4
1 def get_active(active=None): 2 if active : ^ 3 return active 4 return True 5 6 print(get_active(False))
Falseという真偽値も、意図的に渡された値の1つです。if active:で済ませると、Falseが「値が無い」と誤判定されます。
直し方: active を active is not None にします。
パターン5
1 def get_data(data=None): 2 if data : ^ 3 return data 4 return {"default": 1} 5 6 print(get_data({}))
空の辞書も同じくfalsyです。呼び出し側が意図的に空の辞書を渡しても、is not Noneで判定しない限り無視されてしまいます。
直し方: data を data is not None にします。
よくある誤解
if x: と if x is not None: は多くの場合同じ結果になるため、違いに気づかないまま使われがちです。0や空文字列を正当な入力として扱いたい場面で初めて問題が表面化します。
実務での勘所
真偽の判定は、Pythonが暗黙にbool(x)を呼び出すことで行われます。この結果は、そのオブジェクトが__bool__を実装していればその戻り値、実装していなければ__len__()の結果が0かどうかで決まります(それも無ければ常にTrue)。空リストや空文字列がfalsyになるのは、それぞれの__len__が0を返すからです。0や空文字列を「値が渡された」として正しく扱いたい場合、if x:ではなくif x is not None:と書けば、falsyだが正当な値であるケースと「本当に何も渡されていない」ケースを区別できます。