鈴木たかのり
本連載でも過去にいくつも型ヒント関連の記事があります。このようによりよいPythonコードを書くための型ヒントが、Pythonバージョンの更新に伴って追加されています。
- 2022年9月:Python最新バージョン対応!
より良い型ヒントの書き方 | gihyo. jp - 2023年1月:O/
Rマッパーの型チェックを強化できるPython 3. 11の新機能 Data Class Transforms (PEP 681) | gihyo. jp - 2023年5月:Python 3.
11の新機能:型チェッカーでロジックの間違いを検出できるtyping. assert_ never関数とtyping. Never型 | gihyo. jp - 2023年9月:Python 3.
12の新機能 「PEP 692: Using TypedDict for more precise **kwargs typing」 の紹介 | gihyo. jp
PEP 729 – Typing governance process:型ヒントのガバナンス
今回調べて知ったのですが、以下のドキュメント
PEP 729では型ヒントの保守、開発を行うPython型ヒント評議会
最初に書いたとおりPEP 729はSCによって2023年11月に採択され、現在5名の初期メンバーがSCにより任命されています。5名のメンバーは、以下のように型ヒントや型関連のツールに習熟した開発者が選ばれています。
- Eric Traut
(Pyright、PEP 647、PEP 681とPEP 695の著者) - Guido van Rossum
(Pythonコア開発者、PEP 484とPEP 526の著者) - Jelle Zijlstra
(Pythonコア開発者、typeshed、pyanalyze、PEP 688とPEP 702の著者) - Rebecca Chen
(pytype) - Shantanu Jain
(Pythonコア開発者、typeshed、mypy)
現在のメンバーは以下のリポジトリで記録されています。メンバー数は3~5名で、最長連続5年などの制限があります。
評議会はその取り組みの一部として、以下のことを行います。
- 仕様に準拠したテストスイートの作成
- 型システムの仕様の作成
- 型システムのユーザー向けリファレンスの作成
なお、Python Steering Councilでの運営は、Guido van Rossum氏がBDFLから引退したことを受け、2019年から始まっています。SCについて詳細を知りたい方は以下の参考資料を確認してください。
- PEP 8016 – The Steering Council Model
- 世界最大のPythonカンファレンス
「US PyCon 2019」 レポート 第3回 3日目朝のLT紹介、キーノートはPython仕様策定のキーパーソンによるパネル | gihyo. jp
型ヒントのドキュメント
上記の評議会の成果のひとつとして、型ヒント、型システムを使用するユーザー向けのリファレンスドキュメントが以下のサイト
- Static Typing with Python
- URL:https://
typing. readthedocs. io/

いままで型ヒントについてはPEPのみが仕様書で、PEPドキュメント自体は仕様を議論するためのドキュメントのため、ユーザー用のドキュメントとしては適切ではありません。そこで、型システムについてのユーザー向けドキュメントが作成されました。このドキュメントでは型システムのガイド、リファレンス、仕様が書かれています。また、型関連ツールが紹介されています。
仕様

型ヒントの公式ドキュメントは以下のリポジトリで管理されています。
@override
デコレーター
- Python公式ドキュメント:@typing.
override - 型ヒントドキュメント:@override
- PEP:PEP 698 – Override Decorator for Static Typing | peps.
python. org
Python 3.@override
というデコレーターが追加されました。
このデコレーターはクラスを継承したときに、サブクラスがスーパークラスの属性やメソッドをオーバーライドしていることを表します。もし、このデコレーターが付いている属性やメソッドが、実際にはなにもオーバーライドしていない場合は、型チェッカーはエラーを出力します。こうすることで
以下のサンプルコードでは、Pet
を継承したFerret
サブクラスを作成しています。サブクラスでは2つのメソッドを定義して、両方に@override
デコレーターを指定しています。
from typing import override
class Pet:
"""ペットを表すクラス"""
name: str
def sleep(self) -> None:
print(f"{self.name}-chan is sleeping.")
def eat(self) -> None:
print(f"{self.name}-chan is eating.")
class Ferret(Pet):
"""フェレットを表すクラス"""
@override
def sleep(self) -> None: # OK
print(f"Ferret, {self.name}-chan is sleeping.")
@override
def eet(self) -> None: # NG
print(f"Ferret, {self.name}-chan is eating.")
pyrightでこのコードをチェックするとeet
メソッドにoverride
マークが付いているが、ベースメソッドが存在していない」
% pyright override_sample.py /.../override_sample.py /.../override_sample.py:22:9 - error: Method "eet" is marked as override, but no base method of same name is present (reportGeneralTypeIssues) 1 error, 0 warnings, 0 informations
このエラーは、サブクラスで本来eat
と書くべきところをeet
と間違えているために発生しています。この間違いに気がつかないと、Ferret.
を呼び出した時に親クラスのメソッドが呼び出されてしまいます。@override
を書くことによって、pyright、mypyなどの型チェッカーでチェックできるようになります。
TypedDict
でRequired
とNotRequired
を使用する
- Python公式ドキュメント:typing.
Required - 型ヒントドキュメント:Required and NotRequired
- PEP:PEP 655 – Marking individual TypedDict items as required or potentially-missing | peps.
python. /org
Python 3.Required
とNotRequired
が追加されました。この2つの型ヒントは、TypedDict
と組み合わせて使用します。TypedDict
で辞書の各キーに対して型ヒントを定義し、各キーに対して必須、非必須を指定できます。
TypedDict
の基本
まずはTypedDict
の動作を確認します。以下のコードでは辞書の3つのキーname
、farm
、age
)str
やint
を指定しています。
from typing import TypedDict
class Ferret(TypedDict):
"""フェレットを表す辞書"""
name: str
farm: str
age: int
guri1: Ferret = {"name": "guri", "farm": "Canadian", "age": 5} # OK
guri2: Ferret = {"name": "guri", "farm": "Canadian", "age": "five"} # NG
guri3: Ferret = {"name": "guri", "age": 5} # NG
このコードをpyrightでチェックすると、2番目と3番目のパターンでエラーが発生します。12行目はage
にはint
を指定すべきところをstr
を指定しているためにエラーになっています。13行目はfarm
キーが指定されていないためにエラーとなっています。
% pyright typeddict_sample1.py /.../typeddict_sample1.py /.../typeddict_sample1.py:12:61 - error: Type "dict[str, str]" is not assignable to declared type "Ferret" "Literal['five']" is not assignable to "int" (reportAssignmentType) /.../typeddict_sample1.py:13:17 - error: Type "dict[str, str | int]" is not assignable to declared type "Ferret" "farm" is required in "Ferret" (reportAssignmentType) 2 errors, 0 warnings, 0 informations
NotRequired
を使用
farm
キーを非必須にするためにNotRequired
を使用します。型ヒントにNotRequired[str]
と書くことで、このキーが非必須
from typing import NotRequired, TypedDict
class Ferret(TypedDict):
"""フェレットを表す辞書"""
name: str
farm: NotRequired[str] # farmを非必須にする
age: int
gura1: Ferret = {"name": "gura", "farm": "Path Valley", "age": 6} # OK
gura2: Ferret = {"name": "gura", "farm": "Path Valley", "age": "six"} # NG
gura3: Ferret = {"name": "gura", "age": 6} # OK
このコードをpyrightでチェックすると、farm
キーを指定していない13行目がエラーではなくなります。
% pyright typeddict_sample2.py /.../typeddict_sample2.py /.../typeddict_sample2.py:12:64 - error: Type "dict[str, str]" is not assignable to declared type "Ferret" "Literal['six']" is not assignable to "int" (reportAssignmentType) 1 error, 0 warnings, 0 informations
Required
を使用
TypedDict
でtotal=False
と指定するとすべてのキーが非必須となります。その場合、逆にRequired
を使用して必須に指定できます。以下のコード例ではname
とage
のみを必須としています。
from typing import Required, TypedDict
class Ferret(TypedDict, total=False):
"""フェレットを表す辞書"""
name: Required[str]
farm: str
color: str
age: Required[int]
seven1: Ferret = {"name": "seven", "farm": "Far Farm", "age": 6} # OK
seven2: Ferret = {"name": "seven", "color": "Black Self", "age": 6} # OK
seven3: Ferret = {"name": "seven", "age": 6} # OK
seven3: Ferret = {"name": "seven", "color": "Black Self"} # NG
上記のコードをpyrightでチェックすると、最後のパターンで必須Required
)age
が指定されていないためエラーとなります。
% pyright typeddict_sample3.py /.../typeddict_sample3.py /.../typeddict_sample3.py:15:18 - error: Type "dict[str, str]" is not assignable to declared type "Ferret" "age" is required in "Ferret" (reportAssignmentType) 1 error, 0 warnings, 0 informations
任意の文字列リテラル型
- Python公式ドキュメント:typing.
LiteralString - 型ヒントドキュメント:LiteralString
- PEP:PEP 675 – Arbitrary Literal String Type | peps.
python. org
Python 3.LiteralString
が追加されました。この型ヒントは文字列リテラルのみを表します。str
型ではなく、文字列リテラルで作成した文字列のみで構成された文字列のみが使用できます。なお、LiteralString
は型チェックにのみに使用される特別な形式で、データ型としては存在しません。
from typing import LiteralString
from pathlib import Path
def eat(name: LiteralString) -> None:
"""LiteralString型のnameのみを受け取る"""
print(f"{name}-chan is eating.")
eat("seven") # OK
name = "seven"
eat(name) # OK
eat(name.title()) # OK
eat("Ferret, " + name) # OK
name = input()
eat(name) # NG
eat(Path("name.txt").read_text()) # NG
上記のコードをpyrightでチェックすると、input()
で入力を受け取る場合とファイルから文字列を取得する場合にLiteralString
ではなくstr
となるためエラーが発生します。.title()
で文字列を変換する場合や+
演算子で文字列を連結していても、元となる文字列がLiteralString
型の場合、変換された文字列もLiteralString
となるためエラーとなりません。
% pyright literalstring_sample.py /..;/literalstring_sample.py /.../literalstring_sample.py:16:5 - error: Argument of type "str" cannot be assigned to parameter "name" of type "LiteralString" in function "eat" "str" is not assignable to "LiteralString" (reportArgumentType) /.../literalstring_sample.py:17:5 - error: Argument of type "str" cannot be assigned to parameter "name" of type "LiteralString" in function "eat" "str" is not assignable to "LiteralString" (reportArgumentType) 2 errors, 0 warnings, 0 informations
この機能は、たとえばプログラム中で実行するSQLやシェルのコマンドに、ユーザーが入力したデータが混入することを防ぐといった用途に使用できます。以下のコード例では、最後の2つのパターンはLiteralString
ではないため、型チェックを実行するとエラーとなります。
from typing import LiteralString
def run_query(sql: LiteralString) -> None:
...
def caller(arbitrary: str, literal: LiteralString) -> None:
run_query("SELECT * FROM animals") # OK
run_query(literal) # OK
run_query("SELECT * FROM " + literal) # OK
run_query(f"SELECT * FROM {literal}") # OK
run_query(arbitrary) # NG
run_query(f"SELECT * FROM animals WHERE name = {arbitrary}") # NG
まとめ
本記事では、最近の型ヒントの動きとして以下を紹介しました。
- PEP 729 – Typing governance processが採択され
「Python型ヒント評議会」 が発足したこと - 型ヒントのドキュメント
「Static Typing with Python」 がtyping. readthedocs. で公開されていることio
また、最近追加された以下の型ヒントを紹介しました。
- オーバーライドしたメソッドに指定する
@override
デコレーター TypedDict
の必須、非必須のキーを指定するRequired
、NotRequired
- 文字列リテラルのみを含む
LiteralString
評議会による運営により、今後も継続的に型システムに関する機能が追加・