5.

Python 論理演算子 and / or / not|短絡評価と bool を返さない挙動

編集
この記事の要点
  • Python の論理演算子は記号ではなく英単語and / or / not
  • andor は bool を返さない。評価を止めた側のオペランドをそのまま返す
  • 短絡評価: and は左が偽なら右を評価しない、or は左が真なら右を評価しない
  • 偽と判定されるのは False None 0 0.0 "" [] () {} set() など。それ以外は真
  • x or "既定値"0"" も既定値に置き換わる。None だけ弾きたいなら if x is None

3 つの論理演算子

演算子意味他言語での書き方
and両方が真なら真&&
orどちらかが真なら真||
not真偽を反転!

Python で & | を書くとビット演算子になります(ビット演算子)。True & False は動いてしまうので、間違えても気づきにくい点に注意してください。

返り値は bool ではない

print(0 or "default")        # default   左が偽 → 右をそのまま返す
print("value" or "default")  # value     左が真 → 左をそのまま返す
print(1 and 2)               # 2         両方真 → 最後を返す
print(0 and 2)               # 0         左が偽 → 左を返す(右は評価しない)

print(type(1 and 2))         # <class 'int'>   bool ではない
print(bool(1 and 2))         # True                明示的に bool 化

この性質を使った x = arg or default は Python でよく見る書き方です。ただし後述の落とし穴があります。

短絡評価

def heavy():
    print("評価された")
    return True

print(False and heavy())   # False   heavy() は呼ばれない
print(True or heavy())     # True    heavy() は呼ばれない

# 安全な事前チェックに使える
items = []
if items and items[0] == "x":       # items が空でも IndexError にならない
    print("先頭は x")

user = None
if user is not None and user.is_admin:   # None なら属性アクセスしない
    print("管理者")

真偽の判定ルール

# 偽と判定されるもの
for v in [False, None, 0, 0.0, 0j, "", [], (), {}, set(), range(0)]:
    assert not v

# それ以外はすべて真
for v in [True, 1, -1, 0.1, "0", "False", [0], {0: 0}]:
    assert v

# 空かどうかの判定は len() を書かずに直接
data = []
if not data:
    print("空です")        # Pythonic
# if len(data) == 0:      冗長

"0""False"空でない文字列なので真です。設定値を文字列で受け取ったときの判定ミスの原因になります。

or による既定値の落とし穴

def show(count=None):
    n = count or 10        # 「未指定なら 10」のつもり
    print(n)

show()        # 10   意図どおり
show(5)       # 5    意図どおり
show(0)       # 10   ← 0 を渡したのに 10 になる

# None だけを既定値に置き換えたいとき
def show2(count=None):
    n = 10 if count is None else count
    print(n)

show2(0)      # 0    意図どおり

空文字列・空リストでも同じことが起きます。「未指定」と「ゼロ・空」を区別したいなら is None で判定するのが確実です。

not の優先順位

# not は and / or より強く、比較より弱い
print(not 1 == 2)          # True    not (1 == 2) と解釈される
print(not True and False)  # False   (not True) and False

# 「含まれていない」は not in が読みやすい
items = [1, 2, 3]
print(5 not in items)      # True
print(not 5 in items)      # 同じ結果だが not in を使う

複数条件をまとめる書き方

code = "b"

# or を並べるより in
if code in ("a", "b", "c"):
    print("対象")

# すべて / どれか は all() と any()
values = [1, 2, 3]
print(all(v > 0 for v in values))   # True   すべて正
print(any(v > 2 for v in values))   # True   1 つでも 2 超え

# 空のときの挙動に注意
print(all([]))   # True    「反例が無い」ので真
print(any([]))   # False

関連

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 算術演算子
  2. 文字列演算子
  3. 代入演算子
  4. 比較演算子
  5. 論理演算子
  6. ビット演算子

最近更新/作成されたページ