SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Pythonの新機能を知ろう!

最新版Python3.12を使いこなす! 型引数や文法関連の新機能を3.10からの変遷で紹介

Pythonの新機能を知ろう! 第3回

  • X ポスト
  • このエントリーをはてなブックマークに追加

match文で、switch文に相当する条件分岐の記述が可能に[3.10]

 ここからは、文法関連の機能を紹介していきます。C言語をはじめとする多くの言語には、値によって処理を分岐させるswitch文があります。これに相当するmatch文が、Python 3.10で導入されました。Pythonのリリース以来switch文が長い間存在していませんでしたが、ここに来て他の言語と同様な条件分岐を記述できるようになりました。

match文と基本的なパターン

 match文は、C言語などにおけるそれによく似ています。以下のリストは、match文の基本型です。

match 値:
    case パターン1:
        処理1
    case パターン2:
        処理2
    ……
    case _:
        全パターンに一致しなかったときの処理

 指定される値が一致したパターンに対応する処理が実行されます。最後のパターン「_」(アンダースコア)はワイルドカードであり、C言語などのswitch文におけるdefaultに相当します。すなわち、いずれのパターンにも一致しなかった場合、ということになります。ワイルドカードが指定されていない場合、一致するパターンがないとmatch文は何もしない文となります。また、処理を区切るbreak文のようなものも不要です。

 こう見ると、Pythonでmatch文を使うのは、switch文になじみがあれば非常に簡単です。以下のリストは、match文の典型的な例です。

match.py
month: int = 2

match month:
    case 1 | 3 | 5 | 7 | 8 | 10 | 12:
        print('31 days')
    case 4 | 6 | 9 | 11:
        print('30 days')
    case 2:
        print('28 or 29 days')
    case _:
        print('Bad month')
# 実行結果:28 or 29 days

 このように、パターンにリテラル値を記述すれば一致する処理が実行されます。リテラル値は、バー「|」で区切ることで「そのいずれか」を表現できます。match文のパターン指定はタプルやリスト、辞書にも対応したものとなっており、複雑なパターンマッチングが可能となっています。そのうち、タプルなどのシーケンスへのマッチングと、辞書へのマッチングを紹介します。

シーケンスへのマッチング

 以下のリストは、タプルをパターンマッチングで仕分ける例です。関数に与えられるタプルは不定長であり、その長さは1番目の要素('line'など)で決まります。おのおののパターンでは、1番目の要素をリテラルで固定し、それで決まる2番目以降の要素を変数で指定しています。タプルの要素の個数が一致すれば、変数には実際の値が入るので、それを処理部分で参照できます。なお、1番目の要素に'line'を指定しても、さらに2個の要素が続くなどした場合にはパターンはマッチしません。リテラル部分が一致し、全体の個数が一致した場合のみマッチしたと見なされます。

match_tuple.py
def display(item):
    match item:
        case ('line', length):
            print(f'line: {length}')
        case ('triangle', bottom, height):
            print(f'triangle: {bottom}*{height}/2')
        case ('square', long_side, short_side):
            print(f'square: {long_side}*{short_side}')
        case ('trapezoid', top_side, bottom_side, height):
            print(f'trapezoid: ({top_side + bottom_side})*{height}/2')
        case _:
            print('Not supported')

display(('line', 100))
display(('triangle', 100, 200))
display(('square', 200, 200))
display(('trapezoid', 100, 200, 50))
# 実行結果:line: 100
#           triangle: 100*200/2
#           square: 200*200
#           trapezoid: (300)*50/2

辞書へのマッチング

 タプルでは、要素のリテラルや個数でパターンを指定できました。これを辞書でやってみたのが以下のリストです。パターンは辞書の記法でそのまま記述しますが、変数を使って処理内で参照できる点はタプルと同様です。

match_dict.py
def display(item):
    match item:
        case {'type': 'line', 'length': length}:
            print(f'line: {length}')
        case {'type': 'triangle', 'bottom': bottom, 'height': height}:
            print(f'triangle: {bottom}*{height}/2')
        case {'type': 'square', 'long_side': long_side, 'short_side': short_side}:
            print(f'square: {long_side}*{short_side}')
        case {'type': 'trapezoid', 'top_side': top_side, 'bottom_side': bottom_side, 'height': height}:
            print(f'trapezoid: ({top_side + bottom_side})*{height}/2')
        case _:
            print('Not supported')

display({'type': 'line', 'length': 100})
display({'type': 'triangle', 'bottom': 100, 'height': 200})
display({'type': 'square', 'long_side': 200, 'short_side': 200})
display({'type': 'trapezoid', 'top_side': 100, 'bottom_side': 200, 'height': 50})
# 実行結果:line: 100
#           triangle: 100*200/2
#           square: 200*200
#           trapezoid: (300)*50/2

with文の複数リソース指定が改良され、クローズ処理を自動化[3.10]

 ファイルなどのリソースの解放を確実にするために、Pythonにはwith文があります。Javaのtry-with-resources文やC#のusing文に相当するもので、安全にリソースを使う際に便利な機能です。このwith文はPython 3.1で導入されて、その時点から複数のリソースが指定できました。以下のリストでは、3つのファイルを開いて内容を表示しますが、with文により自動的にファイルのクローズ処理が実行されます。

with.py
with open('hello.txt') as file1, open('konnichiwa.txt') as file2, open('bonjour.txt') as file3:
    print(file1.read())
    print(file2.read())
    print(file3.read())

 この例では3つのファイルを指定していますが、ファイル数が増えてくるとwith文が長くなるのが欠点です。カンマのあとで改行するとエラーになりますし、バックスラッシュで行を続けるのもあまり見栄えのよいものではありません。

 これを受けて、Python 3.10ではリソースの指定全体をカッコ()で囲むことで、カンマ後でのバックスラッシュなしの改行が可能になりました。

with.py
with (open('hello.txt') as file1,
      open('konnichiwa.txt') as file2,
      open('bonjour.txt') as file3):
    print(file1.read())
    print(file2.read())
    print(file3.read())

 このように、インデントレベルは自由に調整できますし、バックスラッシュなども不要なので見た目にスッキリします。なお、この記法はPython 3.9ですでに利用可能でしたが、公式にドキュメントに掲載されたのは3.10からです。カッコで括る記法がタプルと同じであるので、サポートには新しいパーサが必要でした。そのパーサに完全に置き換えられたのがPython 3.10なので、公式には3.10からということになっています。

まとめ

 今回は、Python 3.10以降の新機能のうち、ジェネリクスのための新しい型引数構文、**kwargsのより厳密な型付け、オーバーライドデコレータtyping.overrideなどのPython 3.12でサポートされた型関連機能、構造的パターンマッチング、with文の入れ子構文の改良などの文法関連の新機能を中心に紹介しました。

 次回は、ExceptionGroupとTaskGroup、f-strings構文の形式化などの文法関連の新機能、それに改良されたエラーメッセージなどインタープリタの改良を中心に紹介します。

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
Pythonの新機能を知ろう!連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 山内 直(WINGSプロジェクト ヤマウチ ナオ)

WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS Twitter: @yyamada(公式)、@yyamada/wings(メンバーリスト) Facebook <個人紹介> WINGSプロジェクト所属のテクニカルライター。出版社を経てフリーランスとして独立。ライター、エディター、デベロッパー、講師業に従事。屋号は「たまデジ。」。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/18629 2023/11/14 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング