Truthy/Falsyとis vs ==
このトピックを修了すると
Pythonにおいて、ある値が条件文でTrue/Falseとして評価されるかどうかを知り、isと==を正しく使い分けられるようになります。
TruthyとFalsy
Pythonのif文は、True/Falseのみを受け付けるわけではありません。どんな値でも条件として使用できます。
if "hello": print("実行される") # 実行される!
if 0: print("実行されない") # 実行されないPythonはすべての値をTruthy(真とみなす)とFalsy(偽とみなす)に分けます。
Falsy値 — 覚えておけばOK
Falsyな値は決まっています。残りのすべてはTruthyです。
# これらがFalsy (Falseと評価)FalseNone0 # 整数00.0 # 浮動小数点数0"" # 空の文字列[] # 空のリスト{} # 空の辞書set() # 空のセット# 確認してみるvalues = [False, None, 0, 0.0, "", [], {}, set()]for v in values: print(f"{str(v):10} → {bool(v)}")# False → False# None → False# 0 → False# 0.0 → False# → False# [] → False# {} → False# set() → False重要なルール:「空であるか、または0であればFalsy」。これだけ覚えていればOKです。
実践的なパターン — 空の値のチェック
Truthy/Falsyを活用すると、コードが簡潔になります。
# リストが空かどうかを確認items = []
# こう書く必要はないif len(items) > 0: print("存在する")
# こう書けば良いif items: print("存在する")# 文字列が空かどうかを確認name = ""
if name: print(f"こんにちは、{name}")else: print("名前を入力してください")# Noneのチェックとデフォルト値def greet(name=None): name = name or "ゲスト" return f"こんにちは、{name}"
print(greet()) # "こんにちは、ゲスト"print(greet("太郎")) # "こんにちは、太郎"or演算子は、左側がFalsyの場合に右側を返します。デフォルト値のパターンとしてよく使用します。
== — 値が同じか
==は、2つの値が等しいかどうかを比較します。
a = [1, 2, 3]b = [1, 2, 3]
print(a == b) # True — 内容が同じなので2つのリストは異なるオブジェクトですが、含まれている値が同じであるため、==はTrueになります。
print(1 == 1.0) # True — 数値が同じならprint("abc" == "abc") # Trueprint([1] == [1]) # Trueis — 同じオブジェクトか
isは、2つの変数がメモリ上で同じオブジェクトを指しているかどうかを比較します。
a = [1, 2, 3]b = [1, 2, 3]c = a
print(a == b) # True — 値は同じprint(a is b) # False — 異なるオブジェクトprint(a is c) # True — 同じオブジェクトを指しているaとbは内容は同じですが、互いに異なるリストオブジェクトです。c = aは同じリストを指しているので、isはTrueになります。
# id()で確認可能print(id(a)) # 140234567890print(id(b)) # 140234567920 (異なるアドレス)print(id(c)) # 140234567890 (aと同じアドレス)Noneの比較 — isを使うべき理由
result = None
# ✅ 正しい方法if result is None: print("結果なし")
# ❌ 推奨されない方法if result == None: print("結果なし")NoneはPython全体で単一のオブジェクトです。isで比較することで、「これがまさにそのNoneオブジェクトか」を直接確認します。
==は、クラスが__eq__メソッドをオーバーライドすると、予想と異なる動作をする可能性があります。
class Tricky: def __eq__(self, other): return True # 何と比較してもTrue
t = Tricky()print(t == None) # True — 危険!print(t is None) # False — 安全PEP 8(Pythonの公式スタイルガイド)でも、Noneの比較にはisを使用するように明示されています。
整数のキャッシュの罠
a = 256b = 256print(a is b) # True — CPythonが-5〜256を事前にキャッシュ
a = 257b = 257print(a is b) # False — 範囲外なので、別のオブジェクトを生成CPythonは、小さな整数(-5〜256)を事前に作成しておき、再利用します。この範囲内ではisがTrueになりますが、範囲外ではFalseになります。これが値の比較にisを使用すべきでない理由です。isは、None、True、Falseの比較にのみ使用します。
# 文字列でも同様の現象a = "hello"b = "hello"print(a is b) # True — インターニングが発動
a = "hello world!"b = "hello world!"print(a is b) # False — 空白+特殊文字を含むと、インターニングされない関数の引数のデフォルト値とNone
# ❌ 危険なパターンdef add_item(item, items=[]): items.append(item) return items
print(add_item("a")) # ["a"]print(add_item("b")) # ["a", "b"] — 以前の呼び出しの結果が残っている!
# ✅ 安全なパターンdef add_item(item, items=None): if items is None: items = [] items.append(item) return items可変オブジェクト(リスト、辞書)をデフォルト値として使用すると、すべての呼び出しが同じオブジェクトを共有します。Noneをデフォルト値として使用し、関数内で新しいオブジェクトを作成することが、Pythonの標準的なパターンです。
bool()とTruthy/Falsyの活用
# 空の値を簡潔に検証data = {"name": "太郎", "email": "", "phone": None}
# ❌ 長く、繰り返しif data["name"] is not None and data["name"] != "": print("nameが存在する")
# ✅ Truthy/Falsyの活用if data["name"]: print("nameが存在する")
# 有効な値のみをフィルタリングvalues = [0, "", None, "hello", [], [1, 2], False, 42]valid = list(filter(None, values))print(valid) # ["hello", [1, 2], 42]filter(None, iterable)は、Falsyな値をすべて削除します。データの精製でよく使用されるパターンです。
まとめ
| 比較 | 意味 | 使用する場面 |
|---|---|---|
== | 値が同じか | 一般的な値の比較 |
is | 同じオブジェクトか | None、True、Falseの比較 |
!= | 値が異なるか | 一般的な不一致の確認 |
is not | 異なるオブジェクトか | is not None |
# これらのパターンを覚えておきましょうif x is None: # Noneのチェックif x is not None: # Noneでないかチェックif items: # 空でないか(Truthy)if not items: # 空であるか(Falsy)any()とall() — コレクションのTruthyの活用
scores = [85, 92, 0, 78, 95]
print(any(scores)) # True — 少なくとも1つTruthy(0ではないものがある)print(all(scores)) # False — 0がFalsy
# 条件式とともにprint(any(s >= 90 for s in scores)) # True — 90以上があるかprint(all(s >= 60 for s in scores)) # False — すべて60以上かany()とall()は、内部的にTruthy/Falsyの判定を使用します。条件を簡潔に表現する場合に便利です。
短絡評価(Short-circuit)の活用
# or — 最初のTruthyを返す(ない場合は最後の値)name = user_input or "デフォルト名"
# and — 最初のFalsyを返す(ない場合は最後の値)result = data and data[0] # dataが空の場合は[]を返す、そうでない場合は最初の要素orとandは、ブール値を返すのではなく、Truthy/Falsyの判定を停止した時点の値を返します。デフォルト値の設定や、安全なアクセスパターンでよく使用されます。
==とisの違いを理解しないと、見つけにくいバグが発生します。特に、Noneの比較では、==の代わりにisを使用する習慣は、Pythonコードの品質の基本です。