カテゴリー

Python基礎

【Python3.10&パターンマッチ】match文を試してみる

2021年10月11日

こんな人にオススメ

2021年10月4日にpython3.10がリリースされ、新機能としてパターンマッチが追加されたけど、どんなもの?

ということで、今回はpython3.10で新たに追加された新機能「パターンマッチ」について解説する。「match」と「case」を使用して処理を分岐させる構文だ。

似ているものとしてはC言語のswitch文が挙げられる。今までpythonにはこういった条件分岐はなかった。

【C言語&switch文】C言語初心者がswitch文を学ぶ

こんな人にオススメ C言語のsw ...

続きを見る

なお、今回のパターンマッチを使用しなくても、ifを使用することで代用することが可能。だけど、複雑な構造を簡単にかけるっぽい。

python環境は以下。

  • Python 3.10.0

運営者のメガネとです。YouTubeTwitterInstagramも運営中。

自己紹介はこちらから、お問い合わせはこちらからお願いいたします。

運営者メガネ

基本的な書き方

match 調べたいオブジェクト:
    case パターン1:
        処理1
    case パターン2:
        処理2
    case _:
        パターン1, 2以外の場合の処理

基本的な書き方はシンプルで、本当にC言語のswitch文と同じイメージ。ただし、switchとは書かずにmatchと書く。

caseの後に判定したいパターンを入れていき、最後のcase _でパターンに当てはまらないもの全ての処理を行う。

最後のcase _はなくても大丈夫。そのときはパターンから外れると何も起きない。後ほど実行する。

数値でマッチ

# パターンマッチ
def match_simple(val):
    match val:
        case 0:  # valが0の時
            print('0でした')
        case 1:  # valが1の時
            print('1でした')
        case _:  # valが0, 1以外の時
            print('0, 1以外')

まずは数字でパターンマッチする。判定するのは以下の項目。

  • 0
  • 1
  • 上記以外

なお、小数1.を入れたとしても1判定される。

val = 0  # 調べたい変数
match_simple(val)
# 0でした
match_simple(val=10)  # この場合はマッチしないので「case _」に該当
# 0, 1以外

match_simple(val=1.)  # 小数も適用される
# 1でした

orは「|」で指定

# もしくはの時は「|」を使用
def match_or(val):
    match val:
        case 0 | 1:  # valが0か1の時
            print('0もしくは1でした')
        case 1:  # valが1の時(上のcaseで1は取られるのでここは適用されない)
            print('1でした')
        case _:  # valが上記以外の時
            print('0, 1以外')

パターンに「または」を入れたいときは「|」を使用する。上では0もしくは1で判定をしている。

なお、パターン1ですでに1が判定されているので、パターン2の1は判定されない。

match_or(val=0)
# 0もしくは1でした
match_or(val=1)
# 0もしくは1でした
match_or(val=2)
# 0, 1以外

orにするとエラー

# 「|」の代わりに「or」を使用するとエラー
def match_or2(val):
    match val:
        case 0 or 1:  # valが0か1の時
            print('0もしくは1でした')
        case 1:  # valが1の時(上のcaseで1は取られるのでここは適用されない)
            print('1でした')
        case _:  # valが上記以外の時
            print('0, 1以外')

#     case 0 or 1:  # valが0か1の時
#            ^^
# SyntaxError: expected ':'

逆に「|」の代わりに「or」を使用するとこれは文法エラーとなる。

andはそもそもエラー

# andは使えない
def match_and(val):
    match val:
        case 0 & 0.:  # valが0の時
            print('0でした')

#     case 0 & 0.:  # valが0の時
#            ^
# SyntaxError: expected ':'

andの場合はどうかというとこちらも文法エラー。andを使用する例が思いつかなかったので意味わからん判定になっているけどエラー。

後述するがパターンには式は入れられないので、len(val) == 3 and val[0] == 'a'のように文字列の長さと先頭文字の判定を入れることはできない。

上の例では「&」で試したけど、「and」にしてもエラーだった。

case _を省略するとそれ以外は何もしない

# 「case _」を省略するとそれ以外の時には何もしない
def match_no_others(val):
    match val:
        case 0 | 1:  # valが0か1の時
            print('0もしくは1でした')
        case 1:  # valが1の時(上のcaseで1は取られるのでここは適用されない)
            print('1でした')

それ以外のパターンであるcase _を省略することも可能。この場合はそれ以外のパターンでは何もしないことになる。

今回の例だと、01以外の入力では何も起きないことになる。

match_no_others(val=0)
# 0もしくは1でした

match_no_others(val=2)  # 「case _」を省くとそれ以外の判定は何もしないことになる

式は入れられないけど複素数なら大丈夫

# 式は入れられない
val = 1
match val:
    case 0 + 1:
        print('0 + 1を判定')
#     case 0 + 1:
#              ^
# SyntaxError: imaginary number required in complex literal

上で少し書いたけど、パターンの部分に式を入れる事はできない。この例だと0 + 1という式を入れたけどエラー。

しかし、式ではなく複素数とするとエラーとはならない。以下の例では0 + 1jという複素数を使用した。まあ実数と虚数だから分けざるを得ない。

# 複素数なら大丈夫
val = 0 + 1j
match val:
    case 0 + 1j:
        print('0 + 1jを判定')
# 0 + 1jを判定

ifを使うと条件追加(ガード)

# ifを使って条件を追加(ガード)
def match_req(val):
    match val:
        case val if val <= 1:
            print('1以下の値')
        case val if 1 < val <= 2:
            print('1 < val ≤ 2の値')
        case _:
            print('それ以外')

caseのパターンに条件を追加することも可能。これをガードと呼ぶようだ。かっこいい。

これは、caseのパターンに当てはまったものに追加で条件を追加するイメージ。今回だとval1以下かどうかと1を超過して2以下とした。

match_req(val=0)
# 1以下の値
match_req(val=1)
# 1以下の値
match_req(val=1.5)
# 1 < val ≤ 2の値
match_req(val=2)
# 1 < val ≤ 2の値
match_req(val=3)
# それ以外

listのマッチは個数判定

# listでマッチさせるときは要素数で判定
def match_lst(lst):
    match lst:
        case[1]:
            print('[1]でした')
        case[x]:
            print(f"[1]ではなく[{x}]でした")
        case[0, 1]:
            print('[0, 1]でした')
        case[x, y]:
            print(f"[0, 1]ではなく[{x}, {y}]でした")
        case _:
            print('それ以外')

listをパターンに持ってくることも可能。考え方は今までと同じでいける。なお、tupleも同じように可能。

初めのcase[1]を判定し、それ以外の要素数が1つのリストはパターン2の[x]で判定している。その後も同じ感じ。

match_lst(lst=[0])
# [1]ではなく[0]でした
match_lst(lst=[1])
# [1]でした
match_lst(lst=[0, 1])
# [0, 1]でした
match_lst(lst=[10, 11])
# [0, 1]ではなく[10, 11]でした
match_lst(lst=[10, 11, 20])
# それ以外

dictのマッチはkey判定

# 辞書型ではkeyで判定
def match_dct(dct):
    match dct:
        case {'key1': 0, 'key2': x}:
            print('0番目のケース')
        case dict(key1=1, key2=x):  # dict()で書くとスルーされる
            print('1番目のケース')
        case {'key1': 1, 'key2': x}:
            print('2番目のケース')
        case _:
            print('それ以外')

dictもパターンに持ってこれる。dictの場合はちょっと挙動が変になるので、マッチさせる際には注意が必要。

{key:: value}で作成したdictだとちゃんと判定されるけど、dcit(key=value)で作成すると判定されない。

色んなサイトの例を見ても{}を使用するばかりだったので、下手にdictで作成しないほうがいいだろう。

match_dct(dct={'key1': 0, 'key2': 10})
# 0番目のケース
match_dct(dct={'key1': 1, 'key2': 10})
# 2番目のケース
match_dct(dct=dict(key1=1, key2=10))
# 2番目のケース
match_dct(dct={'key1': 2, 'key2': 10})
# それ以外

型で判定

# 型で判定
def match_type(x):
    match x:
        case int():
            print('整数')
        case str():
            print('文字列')
        case list():
            print('リスト')
        case tuple():
            print('タプル')
        case dict():
            print('辞書')

最後は型の判定。caseにはクラス名で入れることもできる。ここでは簡単な型を判定させてみた。

match_type(x=10)
# 整数
match_type(x='10')
# 文字列
match_type(x=[10])
# リスト
match_type(x=(10,))
# タプル
match_type(x={'10': 10})
# 辞書

下手に使うことはないか

今回はpython 3.10の新機能であるパターンマッチを試してみた。これまではifを使ってちまちま書いていたのがmatchを使用することで簡単に書ける。

しかし、実際にはまだこれを活用する場面が思い浮かばないし、下手に使うと他の人が使えないってことになりかねない。

ということで、パターンマッチはしばらくは使わないほうがいいか、自分用に使うのがいいだろう。

関連記事

【辞書の結合】dictのマージ

こんな人にオススメlistは+記号 ...

続きを見る

【astropy&単位】astropyの単位出力書式

こんな人にオススメastropyで数Í ...

続きを見る

【python3.7以降&dictのkeys】ネスト(入れ子)されたdictのkeys一覧をカッコで出力

こんな人にオススメ dictとやら ...

続きを見る

【python3&zip関数】python3系にてzipは一回使ったら消える

こんな人にオススメ python3系でzip& ...

続きを見る

スイッチボット

2022/11/28

【SwitchBotロックレビュー】これからのスタンダードになりうるスマートロック

こんな人にオススメ SwitchBotからスマートロック「SwitchBotロック」が発売された ...

生活に役立つ

2022/11/28

【メガネ厳選】クソ便利に使っているサービスやアイテム達

このページでは執筆者「メガネ」が実際に使って便利だと感じているサ ...

マウス

2022/9/11

【Logicool MX ERGO vs MX Master 3】ERGOをメインにした決定的な理由

こんな疑問・お悩みを持っている人におすすめ 執筆者はLogicoolのハイエンӠ ...

完全ワイヤレスイヤホン(TWS)

2022/11/21

【ながら聴きイヤホン比較】SONY LinkBuds、ambie、BoCoはどれがおすすめ?

こんな人におすすめ 耳を塞がない開放型のイヤホンに完全ワイヤレスӟ ...

macOSアプリケーション

2022/10/15

【M1 Mac】MacBook Proに入れている便利でニッチなアプリを21個紹介する

こんな人におすすめ MacBookを購入してLINEとか必要最低限のアプリは入れた。 ...

完全ワイヤレスイヤホン(TWS)

2022/10/23

【SENNHEISER MOMENTUM True Wireless 3レビュー】高レベルでバランス型の高音質イヤホン

こんな人におすすめ SENNHEISER MOMENTUM True Wireless 3って実際のところどうなの? 評判は良い ...

完全ワイヤレスイヤホン(TWS)

2022/11/21

【SONY WF-1000XM4レビュー】神とゴミのハーフ&ハーフ

こんな人におすすめ SONYのフラグシップモデル「SONY WF-1000XM4」ってどれくらい性 ...

完全ワイヤレスイヤホン(TWS)

2022/8/19

【Nothing ear (1)レビュー】ライトな完成度、アップデートに期待

こんな人にオススメ 完全ワイヤレスイヤホン(TWS)でスケルトンボディ ...

Pythonを学びたいけど独学できる時間なんてない人へのすゝめ

執筆者は大学の研究室・大学院にて独学でPythonを習得した。

でも社会人になったら独学で行うには時間も体力もなくて大変だ。

時間がない社会人だからこそプロの教えを乞うのが効率的。

ここでは色んなタイプに合ったプログラミングスクールの紹介をする。

  • この記事を書いた人

メガネ

ベンチャー企業のWebエンジニア駆け出し。独学のPythonで天文学系の大学院を修了→新卒を1.5年で辞める→転職→今に至る。
常時金欠のガジェット好きでM1 MacBook Pro x Galaxy S22 Ultraの狂人。
人見知りで根暗だったけど、人生楽しもうと思って良い方向に狂う→人生が楽しい

ガジェットのレビューとPythonコードを記事にしています。ぜひ楽しんでください🦊
自己紹介と半生→変わって楽しいの繰り返し

-Python基礎
-