Python match-caseでif-elifチェーンをスッキリ書き換える
問題
APIレスポンスを処理する際、このようなコードになりがちです。
def handle_response(response):
if response['status'] == 200:
return process_data(response['data'])
elif response['status'] == 404:
return None
elif response['status'] == 401 or response['status'] == 403:
raise AuthError()
elif response['status'] >= 500:
raise ServerError()
else:
raise UnknownError(response['status'])
条件がさらに増えると、可読性が大幅に低下します。
解決方法
Python 3.10+のmatch-caseを使うと、はるかにクリーンに書けます。
def handle_response(response):
match response:
case {'status': 200, 'data': data}:
return process_data(data)
case {'status': 404}:
return None
case {'status': 401 | 403}:
raise AuthError()
case {'status': status} if status >= 500:
raise ServerError()
case _:
raise UnknownError(response['status'])
自動的に構造分解が行われるのがポイントです。'data': dataの部分で値を取り出し、そのまま変数にバインドします。
クラスオブジェクトにも使えます。
from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
def describe(point):
match point:
case Point(x=0, y=0):
return "原点"
case Point(x=0, y=y):
return f"Y軸上 ({y})"
case Point(x=x, y=0):
return f"X軸上 ({x})"
case Point(x=x, y=y) if x == y:
return f"対角線上 ({x})"
case _:
return f"一般座標 ({point.x}, {point.y})"
ポイント
match-caseは単なる値の比較ではなく、構造的パターンマッチングです|演算子で複数のパターンを一つにまとめることができますifガード条件で追加のフィルタリングが可能です_はワイルドカードで、任意の値にマッチします(elseの役割)- Python 3.10以上が必須です