Pythonの構造的パターンマッチング:match-case文による高度な条件分岐とデータ抽出

Python 3.10で導入された「構造的パターンマッチング(match 文)」は、単なる値の比較だけでなく、データの構造(リスト、タプル、辞書、オブジェクトなど)に基づいて分岐を行い、同時にその中身を変数に抽出できる強力な機能です。

従来の if-elif-else 文よりも可読性が高く、複雑なデータ構造を扱う際に威力を発揮します。

この記事では、基本的な値のマッチから、オブジェクトの属性マッチまで、match 文の網羅的な使い方を解説します。

目次

基本的な値のマッチとデフォルト処理

変数の値が特定のリテラル(数値や文字列など)と一致するかどうかを判定します。これは if 文や、他言語の switch 文に近い使い方です。

case _: は「ワイルドカード」と呼ばれ、どのパターンにも一致しなかった場合のデフォルト処理(else に相当)を記述します。

http_status = 404

match http_status:
    case 200:
        print("リクエスト成功")
    case 404:
        print("ページが見つかりません")
    case 500:
        print("サーバーエラー")
    case _:
        # どの条件にも当てはまらない場合
        print("不明なステータスコード")

実行結果:

ページが見つかりません

複数の値のマッチ(ORパターン)

パイプ記号 | を使用することで、複数の値のいずれかに一致する場合という条件(OR条件)を記述できます。

role = "editor"

match role:
    case "admin" | "manager":
        print("管理権限があります")
    case "editor" | "viewer":
        print("閲覧権限があります")
    case _:
        print("権限がありません")

実行結果:

閲覧権限があります

条件判定(Guard)

case 文の後ろに if を追加することで、パターンに一致した上で、さらに特定の条件を満たす場合のみ実行するという「ガード条件」を設定できます。

point = 85

match point:
    # 値を変数 p に代入し、その p が 90以上か判定
    case p if p >= 90:
        print(f"スコア: {p} - 素晴らしい成績です")
    case p if p >= 70:
        print(f"スコア: {p} - 合格です")
    case _:
        print("不合格です")

実行結果:

スコア: 85 - 合格です

変数への代入(キャプチャ)

case に変数名を指定すると、マッチした値がその変数に代入されます。これにより、分岐の中でその値を利用できます。

response_code = 418

match response_code:
    case 200:
        print("OK")
    # 変数 code に値をキャプチャする
    case code:
        print(f"エラーが発生しました。コード: {code}")

実行結果:

エラーが発生しました。コード: 418

シーケンスのアンパック(タプル・リスト)

リストやタプルなどのシーケンス構造をマッチさせ、内部の要素を個別の変数に取り出すことができます。

# 座標データ (x, y)
coordinate = (15, 20)

match coordinate:
    case (0, 0):
        print("原点です")
    case (0, y):
        print(f"Y軸上にあります: y={y}")
    case (x, 0):
        print(f"X軸上にあります: x={x}")
    case (x, y):
        print(f"座標: x={x}, y={y}")

実行結果:

座標: x=15, y=20

先頭とそれ以外に分けて代入(Restパターン)

アスタリスク * を付けた変数を使用すると、リストの残りの要素をまとめてリストとして受け取ることができます。コマンドライン引数の解析などに便利です。

command = ["move", 10, 20, 5]

match command:
    case ["quit"]:
        print("終了します")
    # 先頭が "move" で、残りの要素を params に格納
    case ["move", *params]:
        print(f"移動コマンド: パラメータ {params}")
    case _:
        print("不明なコマンド")

実行結果:

移動コマンド: パラメータ [10, 20, 5]

辞書の一致と値の取得

辞書の構造に基づいてマッチングを行います。辞書のマッチングでは、指定したキーが存在するかどうか(部分一致)をチェックします。同時に、特定のキーの値をキャプチャすることも可能です。

user_info = {"id": 101, "role": "admin", "name": "tanaka"}

match user_info:
    # "role" が "guest" の場合
    case {"role": "guest"}:
        print("ゲストユーザーです")
    
    # "role" が "admin" で、"name" を変数 n にキャプチャする場合
    case {"role": "admin", "name": n}:
        print(f"管理者としてログイン: {n}")
    
    case _:
        print("一般ユーザーです")

実行結果:

管理者としてログイン: tanaka

オブジェクトの属性一致

クラスのインスタンスに対しても、その型と属性に基づいてマッチングを行えます。

class Button:
    def __init__(self, label, color):
        self.label = label
        self.color = color

# ボタンのインスタンス
ui_element = Button("Submit", "blue")

match ui_element:
    # Buttonクラスで、colorが "red" の場合
    case Button(color="red"):
        print("危険なボタンです")
    
    # Buttonクラスで、labelを変数 l にキャプチャする場合
    case Button(label=l, color="blue"):
        print(f"青色のボタン: {l}")
    
    case _:
        print("その他のUI要素")

実行結果:

青色のボタン: Submit

まとめ

Pythonの構造的パターンマッチング(match 文)は、以下のような操作を統一的な構文で記述できます。

  • 単純な値の比較
  • 変数のキャプチャ(代入)
  • ガード条件による詳細な判定
  • リストや辞書の構造解析とアンパック
  • オブジェクトのクラスと属性の判定

複雑な条件分岐を簡潔に記述するために、積極的に活用してください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次