and / or の短絡評価を活用したイディオム集(Python)
Python の and と or は単なる論理演算子ではない。短絡評価(short-circuit evaluation)という仕組みにより、条件が確定した時点で評価を打ち切り、最後に評価した値をそのまま返す。この特性を理解すると、簡潔で Python らしいコードが書けるようになる。
短絡評価の基本ルール
and と or の評価ルールは以下の通りだ。
左辺が Falsy なら左辺を返す。左辺が Truthy なら右辺を返す。
左辺が Truthy なら左辺を返す。左辺が Falsy なら右辺を返す。
重要なのは、返り値が True や False ではなく「最後に評価したオブジェクトそのもの」という点だ。
# and は左辺が Falsy なら左辺を返す
print(0 and "hello") # 0
print("" and [1, 2, 3]) # ""
# and は左辺が Truthy なら右辺を返す
print(1 and "hello") # "hello"
print([1] and {"a": 1}) # {"a": 1}
# or は左辺が Truthy なら左辺を返す
print(1 or "hello") # 1
print("hi" or []) # "hi"
# or は左辺が Falsy なら右辺を返す
print(0 or "hello") # "hello"
print("" or "default") # "default"イディオム 1:デフォルト値の設定
or を使った最も一般的なイディオムが、デフォルト値の設定だ。
# ユーザー入力が空なら "Guest" を使う
name = user_input or "Guest"
# 辞書から取得した値が None や空なら代替値を使う
config = settings.get("timeout") or 30
# 環境変数が未設定ならデフォルトを使う
import os
debug_mode = os.environ.get("DEBUG") or "false"ただし、このイディオムには落とし穴がある。0 や False も Falsy なので、これらが有効な値として使われる場合は意図しない動作になる。
# 落とし穴:0 が有効な値の場合
count = user_count or 10 # user_count が 0 だと 10 になってしまう
# 対策:None との比較を明示する
count = user_count if user_count is not None else 10
# Python 3.8 以降ならウォルラス演算子も使える
count = 10 if (c := user_count) is None else cイディオム 2:条件付き関数呼び出し
and を使うと、条件が成立したときだけ関数を呼び出せる。
# callback が設定されていれば呼び出す
callback and callback()
# debug フラグが True なら出力する
debug and print(f"[DEBUG] value = {value}")
# リストが空でなければ最初の要素を処理する
items and process(items[0])これは以下の if 文と等価だが、1 行で書けるため式として扱いたい場合に便利だ。
# 上記と等価な if 文
if callback:
callback()
if debug:
print(f"[DEBUG] value = {value}")
if items:
process(items[0])イディオム 3:最初の Truthy 値を取得
複数の候補から最初に見つかった Truthy 値を取得するパターン。
# 複数の設定源から最初に見つかった値を使う
import os
config_value = (
os.environ.get("APP_CONFIG")
or load_from_file()
or load_from_database()
or "default"
)
# ユーザー名の優先順位付き取得
display_name = user.nickname or user.username or user.email or "Anonymous"このパターンでは、左から順に評価され、最初に Truthy な値が見つかった時点で残りは評価されない。つまり load_from_file() が Truthy を返せば load_from_database() は呼ばれない。
イディオム 4:すべての条件を満たす最後の値
and を連鎖させると、すべてが Truthy な場合のみ最後の値を返せる。
# すべての条件を満たす場合のみ結果を返す
result = user and user.is_active and user.permissions and "allowed"
# 上記は以下と等価
if user and user.is_active and user.permissions:
result = "allowed"
else:
result = None # または Falsy だった値イディオム 5:辞書やリストの安全なアクセス
短絡評価を使って、存在確認とアクセスを同時に行える。
# 辞書のネストした値を安全に取得
data = {"user": {"profile": {"name": "Alice"}}}
# and でチェーンすると途中で None なら止まる
name = data.get("user") and data["user"].get("profile") and data["user"]["profile"].get("name")
# ただし、これは複雑になりがち
# Python 3.8 以降ならウォルラス演算子で改善できる
if (user := data.get("user")) and (profile := user.get("profile")):
name = profile.get("name")より現代的なアプローチとしては、dict.get() のチェーンや例外処理、あるいは専用ライブラリの使用が推奨される。
イディオム 6:三項演算子の代替
古い Python コードでは、or と and を組み合わせて三項演算子の代わりにしていた。
# 古いイディオム(Python 2.4 以前)
result = condition and true_value or false_value
# 現在の三項演算子(Python 2.5 以降)
result = true_value if condition else false_valueただし、古いイディオムには true_value が Falsy の場合に正しく動作しないバグがある。現在は三項演算子を使うべきだ。
# バグの例
condition = True
true_value = 0 # Falsy
false_value = 100
# 古いイディオム:期待は 0 だが 100 が返る
result = condition and true_value or false_value
print(result) # 100(バグ!)
# 三項演算子:正しく 0 が返る
result = true_value if condition else false_value
print(result) # 0短絡評価の副作用を利用するパターン
短絡評価では、評価されなかった式の副作用は発生しない。これを意図的に利用することもある。
# ログ出力を条件付きで行う
verbose and log.debug(f"Processing {item}")
# キャッシュがなければ計算する
cached_value or compute_and_cache()
# ファイルが存在しなければ作成する
os.path.exists(path) or create_file(path)ただし、副作用を伴う式を短絡評価に含めると、コードの意図が分かりにくくなる。可読性を優先するなら、明示的な if 文を使う方がよい場合も多い。
まとめ
短絡評価のイディオムは Python らしい簡潔なコードを書くのに役立つが、使いすぎると可読性を損なう。以下の指針を参考にするとよい。
デフォルト値の設定(value or default)、単純な条件付き実行(flag and action())など、意図が明確なパターン。
複雑なネスト、副作用を伴う複数の式、0 や False が有効値になりうる場面。明示的な if 文や三項演算子を使う方がよい。



