カテゴリー

Python基礎

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

2021年10月11日

こんな人にオススメ

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

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

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

なお、今回のパターンマッチを使用しなくても、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のマージ

続きを見る

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

続きを見る

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

続きを見る

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

続きを見る

ガジェット

2023/9/18

【デスクツアー2022下半期】モノは少なく、でも効率的に Desk Updating #0

今回はガジェットブロガーなのにデスク環境を構築していない執筆者の ...

ライフハック

2023/9/16

【Audible vs YouTube Premium】耳で聴く音声学習コンテンツを比較

ワイヤレスイヤホンが普及し耳で学習することへのハードルが格段に下 ...

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

2023/9/18

【SENNHEISER MOMENTUM True Wireless 3レビュー】全てが整ったイヤホン

今回は高音質・高機能なSENNHEISERのフラグシップ完全ワイヤレスイヤホン「SENNH ...

ライフハック

2023/3/11

【YouTube Premiumとは】メリットしかないから全員入れ

今回はYouTube Premiumを実際に使ってみてどうなのか、どんなメリット/デメリット ...

マウス

2023/8/17

【Logicool MX ERGOレビュー】疲れない作業効率重視トラックボールマウス

こんな人におすすめ トラックボールマウスの王道Logicool MX ERGOが気になるけどऩ ...

ベストバイ

2023/9/18

【ベストバイ2022】今年買って良かったモノのトップ10

2022年ベストバイ この1年を振り返って執筆者は何を買ったのか。ガジェッ& ...

スマホ

2023/1/15

【楽天モバイル×povo2.0の併用】月1,000円の保険付きデュアルSIM運用

こんな人におすすめ 楽天モバイルとpovo2.0のデュアルSIM運用って実際のとこ ...

マウス

2023/9/16

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

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

macOSアプリケーション

2022/9/30

【Chrome拡張機能】便利で効率的に作業できるおすすめの拡張機能を18個紹介する

こんな人におすすめ Chromeの拡張機能を入れたいけど、調べても同じような ...

macOSアプリケーション

2023/5/3

【Automator活用術】Macで生産性を上げる作業の自動化術

今回はMacに標準でインストールされているアプリ「Automator」を使ってできる ...

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

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

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

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

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

  • この記事を書いた人

メガネ

Webエンジニア駆け出し。独学のPythonで天文学系の大学院を修了。常時金欠のガジェット好きでM2 Pro MacBook Pro(30万円) x Galaxy S22 Ultra(17万円)使いの狂人。自己紹介と半生→変わって楽しいの繰り返しレビュー依頼など→お問い合わせ運営者情報、TwitterX@m_ten_pa、 YouTube@megatenpa、 Threads@megatenpa

-Python基礎
-