かゆい所に手が届く解説

Python 3.10の新機能!match/case文を超初心者向けにわかりやすく解説【実用例付き】

Python 3.10の新機能!match/case文を超初心者向けにわかりやすく解説【実用例付き】

Python 3.10で導入されたmatch/case文をご存じですか?

他のプログラミング言語には「switch/case文」が存在しますが、Pythonにはありません。

*下記の記事では、switch/caseの処理をPythonのif文で処理する方法を解説しています。

似ているようで似ていない?

Pythonのmatch/case文は、伝統的なswitch/case文の欠点や制限が解消され、可読性や効率を向上させる強力なツールであり、非常にパワフルです。

この記事では、超初心者でも簡単に理解できるように、Pythonの新しいmatch/case文の基本的な使い方からswitch/case文との違いを詳しく解説します!

丁寧に解説しますが、if/else/elif を理解しているとより分かりやすいのでおススメです。

match/case文とは?

Pythonの新しい機能として導入されたパターンマッチングの仕組みです。

単純な値の比較から複雑なデータ構造のマッチングまで、幅広く使えます。

もし、あなたがswitch/case文をご存じなら、全く比較にならないほど便利で驚くことでしょう。

大げさではなく、それほど便利な構文です。

基本的な使い方

リテラルのマッチング

一致する値を見つける基本的な使い方から確認しましょう。

変数evaluation には、「B」が入っています。

evaluation = 'B'

match evaluation:
    case 'A':
        print('あなたは素晴らしい!')
    case 'B':
        print('もう少し頑張りましょう')
    case 'C':
        print('あと少しで卒業できなくなるところでした')
    case 'D':
        print('あなたは卒業ができません')
    case _:
        print('正しい成績を入力してください')

この場合、matchで指定された変数と一致するのは「case ‘B’」です。

実行結果は「もう少し頑張りましょう」となりますね。

従来のswitch/case文でできたことは、この「完全一致」のみです。

Pythonのmatch/case文はこれ以上に優れています!

次から新しいmatch/case文でできることを紹介します。

シーケンスのアンパック

リストやタプルの要素を個別にマッチさせることができます。

これは、従来のswitch/case文ではできなかったことです。

# ユーザー情報のリスト
user_info_list = [("Alice", 30, "Tokyo"), ("Bob", 25), ("Charlie",)]

# ユーザー情報を個別に処理
user = user_info_list[0]
match user:
    case (name, age, city):
        print(f"名前: {name}")
        print(f"年齢: {age} 歳")
        print(f"都市: {city}")
    case (name, age):
        print(f"名前: {name}")
        print(f"年齢: {age} 歳")
        print("都市情報はありません。")
    case _:
        print("無効なユーザー情報です。")

実行結果は、

名前: Alice
年齢: 30 歳
都市: Tokyo

です。

この場合、リストのインデックス[0]はcase (name, age, city)にマッチした結果となります。

もしも、

# ユーザー情報のリスト
user_info_list = [("Alice", 30, "Tokyo"), ("Bob", 25), ("Charlie",)]

# ユーザー情報を個別に処理
user = user_info_list
match user:
    case (name, age, city):
        print(f"名前: {name}")
        print(f"年齢: {age} 歳")
        print(f"都市: {city}")
    case (name, age):
        print(f"名前: {name}")
        print(f"年齢: {age} 歳")
        print("都市情報はありません。")
    case _:
        print("無効なユーザー情報です。")

となる場合、結果は

名前: Bob
年齢: 25 歳
都市情報はありません。

となりますし、

# ユーザー情報のリスト
user_info_list = [("Alice", 30, "Tokyo"), ("Bob", 25), ("Charlie",)]

# ユーザー情報を個別に処理
user = user_info_list
match user:
    case (name, age, city):
        print(f"名前: {name}")
        print(f"年齢: {age} 歳")
        print(f"都市: {city}")
    case (name, age):
        print(f"名前: {name}")
        print(f"年齢: {age} 歳")
        print("都市情報はありません。")
    case _:
        print("無効なユーザー情報です。")

なら、

無効なユーザー情報です。

となります。

defaultが進化した「case _」の役割

switch/case文では、どのcaseにも当てはまらない場合の処理を「default」に記述しました。

match/case文では、どのcaseにも当てはまらない場合の処理を「case _」に記述します。

これは、どのcaseにも当てはまらない場合にマッチするワイルドカードです。

x = 40
match x:
    case 10:
        print("It's 10!")
    case 20:
        print("It's 20!")
    case _:
        print("It's something else.")

実行結果は以下のようになります。

It's something else.

さらに複雑な処理も可能!

もう少し複雑な処理について紹介します。

次のリストがあります。

これは、動物に対する鳴き声を示したタプルをセットしています。

animals = [
    ("cat", "meow"),
    ("dog", "bark"),
    ("bird", "chirp"),
    ("fish", None)
]

このリストを使って、動物の種類とその特徴に基づいて異なるアクションを実行することができます。

for animal, sound in animals:
    match (animal, sound):
        case ("cat", _):
            print(f"A {animal} says {sound}!")
        case ("dog", _):
            print(f"A {animal} says {sound}!")
        case ("bird", _):
            print(f"A {animal} says {sound}!")
        case (_, None):
            print(f"A {animal} doesn't make a sound.")
        case _:
            print(f"I don't know what sound a {animal} makes.")

この例では、match/caseを使用して、動物の種類とその特徴に基づいて異なるメッセージを出力しています。

結果は以下の通りです。

A cat says meow!
A dog says bark!
A bird says chirp!
A fish doesn't make a sound.

このように、for文と組み合わせてmatch/caseを使用すると、複雑な条件やパターンに基づいて異なるアクションを実行することが簡単になります。

場合によって、for文のみで処理するよりも分かりやすくなります。

他のプログラミング言語のswitch/caseとの違い

伝統的なswitch/caseは、単純な値の比較に使用されます。

Pythonのmatch/caseは、データの構造やパターンに基づいてマッチングを行うことができるのが特徴です。

また、break文を忘れると意図しない動作を引き起こすswitch/caseとは異なり、Pythonのmatch/caseはbreak文が不要なのでその心配もありません。

実用的なスクリプト例①

実際のプログラムで役立つmatch/case文の使用例を紹介します。

次の関数を定義しました。

これは、受け取った引数のtypeによって、処理(計算)を変えることができます。

typeがcircleなら円の面積、rectangleなら四角形の面積を計算します。

def get_shape_description(shape):
    match shape:
        case {"type": "circle", "radius": int(r)}:
            return f"この円の面積は {r * r * 3.14}"
        case {"type": "rectangle", "width": int(w), "height": int(h)}:
            return f"この四角形の面積は{w * h}です"
        case _:
            return "これは円でも四角形でもありません"

この関数を呼び出すパターンをいくつか用意しました。

①円の面積を求める

円の面積を求める場合、typeにcircleを指定し、半径の値(radius)を渡すと計算結果が返ってきます。

circle_shape = {"type": "circle", "radius": 5}
description = get_shape_description(circle_shape)
print(description)

実行結果はこちら。

この円の面積は 78.5

1つ目のcaseが実行されたことが分かります。

②四角形の面積を求める

四角形の面積を求める場合、typeにrectangleを指定し、2辺の長さ(wとh)を渡すと計算結果が返ってきます。

rectangle_shape = {"type": "rectangle", "width": 10, "height": 20}
description = get_shape_description(rectangle_shape)
print(description) 

実行結果はこちら。

この四角形の面積は200です

2つ目のcaseが実行されたことが分かります。

③どれにも当てはまらないとき

用意していたtypeに当てはまらない場合、「case _」の処理が実行されます。

unknown_shape = {"type": "triangle"}
description = get_shape_description(unknown_shape)
print(description)

実行結果はこちら。

これは円でも四角形でもありません

このように、従来のswitch/caseでは実現できない処理が可能です。

実用的なスクリプト例②

もう一つ、別の例を紹介します。

次の関数を定義しました。

これは、「抽選番号」に対する「景品」を選択するものです。

このように条件を複数設定することは、switch/caseではできませんでした。

def get_prize(number):
    match number:
        case 23:
            return "特賞"
        case 11 | 33 | 55 | 77 | 99:
            return "A賞"
        case 3 | 13 | 23 | 33 | 43 | 53 | 63 | 73 | 83 | 93:
            return "B賞"
        case 5 | 29 | 38 | 41 | 58 | 61 | 75 | 87 | 91 | 95:
            return "C賞"
        case _:
            return "残念賞"

この関数を呼び出すパターンをいくつか用意しました。

①B賞となる場合

例として、「63」を指定します。

number = 63
prize = get_prize(number)
print(f"あなたの抽選番号 {number} 番の景品は {prize} です!")

実行結果はこちら。

あなたの抽選番号 63 番の景品は B賞 です!

3つ目のcaseが実行されたことが分かります。

②特賞となる場合

特賞は1つしかありません。

抽選番号を「23」で実行します。

number = 23
prize = get_prize(number)
print(f"あなたの抽選番号 {number} 番の景品は {prize} です!")

実行結果はこちら。

あなたの抽選番号 23 番の景品は 特賞 です!

1つ目のcaseが実行されたことが分かります。

③どれにも当てはまらないとき(残念賞)

特賞、A賞~C賞のいずれにも該当しない場合は「case _」の処理が実行されます。

number = 1
prize = get_prize(number)
print(f"あなたの抽選番号 {number} 番の景品は {prize} です!")

実行結果はこちら。

あなたの抽選番号 1 番の景品は 残念賞 です!

このように、複数の条件をしていした処理も可能です。

範囲を指定できるのか?

上記は複数の条件を指定した処理を紹介しました。

では、「50~59」のような範囲をしていできるのか?というと、現時点ではできません

やろうと思えば

case 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59:

とすることができますが、面倒なので現実的ではありませんよね。

この場合はmatch/case文ではなく条件をマップする方法があります。

def get_grade(score):
    grade_ranges = {
        range(90, 100): "A",
        range(80, 90): "B",
        range(70, 80): "C",
        range(60, 70): "D",
        range(0, 60): "F"
    }

    for score_range, grade in grade_ranges.items():
        if score in score_range:
            return grade

score = 85
grade = get_grade(score)
print(f"あなたの評価 {score} 点は成績 {grade} です!")

このように、範囲ごとに評価される条件を辞書にまとめ、関数内で評価することでスライスのような範囲指定を行う処理が現実的です。

match/case文にこだわる必要はなく、他の方法と比べながら最適な方法を考えましょう。

まとめ

超初心者でも簡単に理解できるように、Pythonの新しいmatch/case文の基本的な使い方からswitch/case文との違いを詳しく解説しました。

match/case文はPython 3.10で導入された強力な新機能です。

複雑な条件分岐やデータ構造のマッチングを簡潔に記述できる点は、他のプログラミング言語で採用されているswitch/case文より使いやすいということが分かりました。

今後もPythonを中心としたプログラミングの情報をお届けします。

Pythonの演習はこちら ▶

以下のメルマガにご登録頂くと、不定期に配信をお届けします。

ぜひ購読してください!

それでは、ステキなPythonライフを!

ABOUT ME
papa3
某教育機関で現役の講師をしながら、ブログとYouTubeでプログラミングの情報を発信しています。個人でもウェブアプリケーション開発と運営をしながら本業収入<副業を目指しています!

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です