|

2025-03-18

Tips

Python の型ヒントで使用する typing.List が非推奨になっていた

Python

Python の型ヒントが想像以上に奥深かった話

皆さんは、Python のコードを記述する際に型ヒントを書いていますか?

 

今回は、そんな型ヒントを記述するときに利用できる typing.List が非推奨になっていたことをきっかけに、型ヒントについて色々と調べてみて、分かったことを自分なりにまとめてみたいと思います。

(※ 型ヒントと似た用語で型アノテーションがあり、厳密には異なる意味のようですが、しばしば似た意味で使用されているため、本記事では型ヒントで統一しております。)

型ヒント

まず、そもそも Python における型ヒントとは、動的型付けという性質を持つ Python において、ある変数や引数にどのようなデータ型が期待されているかを明示的に示すことができるものです。

 

この型ヒントを記述しておくことで、チームでの開発の際にコードの可読性を上げることができたりmypy などの型チェッカーを利用して、実行前にコード内で期待されている型を使用できているかチェックすることができます

 

例えば、以下のように、型ヒントを記述できます。

def foo(x: int, y: str) -> str: return f'{x} {y}'

この場合は、引数 xint 型で 引数 ystr 型であり、戻り値が str 型であることが明示的に示されているということになります。

 

このときに、以下のように型ヒントと実際の戻り値のデータ型が合っていないコードを書いてしまったとします。

def foo(x: int, y: str) -> int: return f'{x} {y}'

 

実際、型ヒントが間違っていてもコードとして動作はしますが、 mypy 等のツールを利用することで、エディタ上でこちらのように誤りを指摘してくれます。 image

 

このように、多少の手間はかかりますが、型ヒントを正しく記述することで、予期せぬエラーの発生や、チーム内での認識の齟齬を未然に防ぐことに繋がります

ジェネリック型

次に、例えば、以下のような関数があったとします。

def bar(x: int): return [x]

このときに、戻り値の型ヒントはどのように記述できるでしょうか?

 

一つは、Python のインタプリタに標準で組み込まれている list 型として定義できます。

def bar(x: int) -> list: return [x]

 

これでも、型チェックには引っかからないのですが、さらに厳密に記述するならば、以下のようにリストの要素の型も記載したいところです。

def bar(x: int) -> list[int]: return [x]

もちろん、こちらも型チェックには引っかかりません。

 

また、こちらの list[int] のような、コンテナオブジェクトに対してパラメータを付与したデータ型をジェネリック型と呼びます。

この例でいうと、list[int] は「整数型の要素を持つリスト」を表すジェネリック型ということになります。

 

と、サラッと書きましたが、実はこの表記方法、Python 3.9 で正式に導入されたもので、それ以前のバージョンでは以下のように記述する必要がありました。

from typing import List def bar(x: int) -> List[int]: return [x]

違いとしては、組み込み型ではなく、標準ライブラリの一つである、typing モジュールを利用しています。

もちろん、別物なので、表記もよく見ると、list ではなく、 List です。

 

弊社内で運用しているコード群も、実はこちらの記法になっており、list との違いを改めて調べていたところ、Python 3.9 以降では typing.List は非推奨であることに気づいたのでした。

なぜ、typing.List が非推奨になったのか?

その理由は、こちらの PEP585 に記載されております。

 

PEP というのは、PEP1 において、以下のように定義されており、Python の設計プロセスなどをまとめた文書のことです。

A PEP is a design document providing information to the Python community, or describing a new feature for Python or its processes or environment.

コーディング規約がまとまっている、PEP8 が有名かと思います。

 

typing.List が非推奨になった理由としては、以下の Abstract 部分から読み取ると、typing モジュールのジェネリック型(typing.List など)と、Python の組み込み型(list など)の二重管理を避けるためであることが分かります。

Python 3.9 から list[int] のような表記が正式にサポートされたため、冗長になった typing.List は非推奨とされたというわけです。

Static typing as defined by PEPs 484, 526, 544, 560, and 563 was built incrementally on top of the existing Python runtime and constrained by existing syntax and runtime behavior. This led to the existence of a duplicated collection hierarchy in the typing module due to generics (for example typing.List and the built-in list).

 

ちなみに、さらに重要なこととして、List を含む typing モジュールのジェネリック型(Dict, Tuple, Set など) は、Python 3.9 以降、組み込み型の dict, tuple, set で直接型パラメータを指定できるようになったため、typing モジュールから 2025年10月までに削除される可能性があります

 

実際、PEP 585 では下記のように言及されています。

The deprecated functionality may eventually be removed from the typing module. Removal will occur no sooner than Python 3.9’s end of life, scheduled for October 2025.

既存のコードの移行方法

では、大量のコード群があるときに、これらをまとめて簡単に修正するにはどうすれば良いのでしょうか?

 

例えば、Ruffpyupgrade といったツールを使えば、Python 3.9 以降の新しい型ヒント (list[int] など) へ自動的に変換できます。

手作業で修正するのは大変ですが、これらのツールを使うことで コード全体をまとめて修正 できるため、移行の負担を大幅に減らせます。

 

Ruff の場合だと、以下のコマンドを実行することで、コードの解析から修正まで一気に実行してくれます。

ruff check --target-version py39 --extend-select UP --fix --unsafe-fixes

 

ちなみに、Ruff の導入については、「Python の Linter / Formatter をまとめられる Ruff を試す」で紹介されているため、是非参考にして頂ければと思います。

まとめ

ここでは、Python の型ヒントの簡単な説明と、Python 3.9 以降でのジェネリック型の型ヒントを記述する上で注意すべき点と、その対応方法について、まとめてみました。

 

今回、このブログを執筆する上で、色々とドキュメントを漁っていると、どんどん知らない情報が出てきて、普段からドキュメントを読む癖をつけるべきだと痛感しました。

特に型ヒントは思った以上に奥が深かったので、皆さんも公式ドキュメントを一読することをオススメします。

 

冒頭でも紹介したように、型ヒントは間違っていても動作はするため、なかなかアップデートに気づきにくいところではありますが、今後も常に最新情報をキャッチアップしていけるようにしたいと思います!


この記事の著者

プロフィール画像

中村 卓矢

朝日放送グループホールディングス株式会社 DX・メディアデザイン局 デジタル・メディアチーム

グループ全体の統合的なデータ基盤の構築・データ分析の支援に従事している。 動画配信・テレビの視聴データ分析等で身につけた幅広い知識を活かして日々奮闘中!