1.

Python の if 文|elif・三項演算子・match 文と条件式の書き方

編集
この記事の要点
  • Python の条件分岐は if / elif / elseelse if ではなく elif
  • 条件にかっこは不要。行末の : と 4 スペースのインデントが必須
  • 空のリスト・空文字・0 は偽。if items: と書けば「中身があるか」の判定になる
  • 三項演算子は A if 条件 else B の順。他言語の ? : とは並びが違う
  • None の判定は == None ではなく is None

基本形

score = 75

if score >= 80:
    grade = "A"
elif score >= 60:          # else if ではない
    grade = "B"
elif score >= 40:
    grade = "C"
else:
    grade = "D"

print(grade)               # B

elif はいくつでも並べられ、else は省略できます。上から順に評価され、最初に真になった枝だけが実行されます。

条件式に書けるもの

書き方意味
a == b / a != b値が等しい / 等しくない
a is b / a is not b同じオブジェクトか
x in items / x not in items含まれているか
and / or / not条件の組み合わせ(&& || ! ではない)
0 < x < 10連鎖比較。x > 0 and x < 10 と同じ
age = 25
if 20 <= age < 65:                 # 連鎖比較が書ける
    print("一般料金")

name = "田中"
if name and name.startswith("田"):   # and は短絡評価。空なら右を見ない
    print("田さん")

if name in ("田中", "鈴木", "佐藤"):   # or を並べるより読みやすい
    print("対象者")

真偽の判定ルール

items = []

if not items:              # Pythonic な「空か」の判定
    print("空です")
# if len(items) == 0:      冗長
# if items == []:          型が違うと成立しない

value = "0"
if value:                  # 空でない文字列なので True
    print("真")            # ← "0" でも真になる点に注意

flag = False
if flag is False:          # bool そのものを見たいときは is
    print("False です")

偽になるのは False None 0 0.0 "" [] () {} set() などです。「値が入っているか」ではなく「未設定か」を見たいときは、次の is None を使います。

None の判定は is None

def show(count=None):
    if count is None:      # 「未指定」だけを弾く
        count = 10
    print(count)

show()        # 10
show(0)       # 0    ← 0 は 0 のまま扱える

def show_bad(count=None):
    if not count:          # 0 や "" も未指定と同じ扱いになってしまう
        count = 10
    print(count)

show_bad(0)   # 10   意図しない結果

== None でも多くの場合は動きますが、__eq__ を独自定義したクラスでは結果が変わり得ます。is None と書くのが唯一の正解です。

三項演算子(条件式)

score = 75
grade = "合格" if score >= 60 else "不合格"     # 真のときの値 が先に来る

# ネストできるが読みにくい。2 段までにとどめる
label = "A" if score >= 80 else "B" if score >= 60 else "C"

# 内包表記の中でよく使う
values = [1, -2, 3]
signs = ["正" if v > 0 else "負" for v in values]   # ['正', '負', '正']

条件 ? A : B の順に慣れていると混乱しやすい部分です。Python は結果を先に読む並びになっています。

ネストを浅くする書き方

# ネストが深い書き方
def price_bad(user):
    if user is not None:
        if user.get("active"):
            if user.get("vip"):
                return 800
            return 1000
    return 0

# 早期 return(ガード節)で平らにする
def price(user):
    if user is None:
        return 0
    if not user.get("active"):
        return 0
    return 800 if user.get("vip") else 1000

「異常なケースを先に返して抜ける」と、本筋の処理がインデント 1 段に収まります。Python はインデントが構文なので、この効果が特に大きくなります。

値による分岐は辞書でも書ける

LABELS = {"start": "開始", "stop": "停止", "pause": "一時停止"}

command = "stop"
print(LABELS.get(command, "不明"))    # 停止   該当なしは既定値

# 処理そのものを割り当てることもできる
ACTIONS = {"start": lambda: print("開始します"),
           "stop": lambda: print("停止します")}
ACTIONS.get(command, lambda: print("不明"))()

elif が 5 個以上続いて値を比べているだけなら、辞書に置き換えると分岐が消えて見通しが良くなります。構造で分岐したい場合は 制御構文match を参照してください。

match 文で分岐する

def handle(event):
    match event:
        case {"type": "click", "x": x, "y": y}:      # 辞書の形で分解
            return f"({x}, {y}) をクリック"
        case {"type": "key", "code": code} if code > 0:
            return f"キー {code}"
        case ["move", *rest]:                        # 残りをまとめて受ける
            return f"移動 {rest}"
        case _:
            return "不明"

print(handle({"type": "click", "x": 1, "y": 2}))     # (1, 2) をクリック

Python 3.10 以降で使えます。値を比べるだけなら if/elif のほうが素直で、match が活きるのは受け取ったデータの構造で分けたいときです。

なお case に単独の名前を書くと「一致」ではなく変数への代入になり、すべてに当たってしまいます。定数と比べたいときは case Color.RED: のようにドット付きの名前で書きます。

複数条件を読みやすくまとめる

user = {"age": 25, "active": True, "plan": "pro"}

# 条件が長くなったら名前を付ける
is_adult = user["age"] >= 20
is_paid = user["plan"] in ("pro", "business")

if is_adult and is_paid and user["active"]:
    print("利用できます")

# すべて / どれか
checks = [is_adult, is_paid, user["active"]]
print(all(checks))      # True   すべて満たす
print(any(checks))      # True   1 つでも満たす

# かっこで改行できる
if (user["age"] >= 20
        and user["plan"] != "free"
        and user["active"]):
    print("利用できます")

条件式に名前を付けると、コメントを書かなくても意図が伝わります。行が長くなるときはかっこで囲んで改行します(行末のバックスラッシュは末尾の空白で壊れるので使いません)。

比較でつまずきやすいところ

print(1 == 1.0)          # True    int と float は比較できる
print(1 == True)         # True    bool は int の一種
print("10" > "9")        # False   文字列は辞書順で比べる
print([1, 2] < [1, 3])    # True    リストは先頭から順に比べる

print(0.1 + 0.2 == 0.3)  # False   浮動小数点の誤差
import math
print(math.isclose(0.1 + 0.2, 0.3))   # True

a, b = [1, 2], [1, 2]
print(a == b)            # True    中身が同じ
print(a is b)            # False   別のオブジェクト

数値を文字列のまま比較しないのが要点です。フォームやファイルから読んだ値は文字列なので、比較の前に int()float() で変換します。

関連

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 条件分岐 (if文)
  2. 繰り返し処理(while文)
  3. 繰り返し処理
  4. 繰り返しの中断 (break)
  5. 繰り返しのスキップ (continue)

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