Traffine I/O

日本語

2022-04-02

PythonのTypedDict

TypedDictとは

TypedDictはPython 3.8で導入された機能であり、typingモジュールの一部です。これを使用すると、辞書の型ヒントを指定することができます。予期されるキーとそれに対応する値の型を示すことができます。TypedDictは実行時にこれらの型を強制するものではありません。代わりに、静的な型チェックツールに使用され、コードの可読性と保守性を向上させます。

TypedDictの作成

PythonでTypedDictを作成するのは簡単です。まず、typingモジュールからTypedDictクラスをインポートします。次に、TypedDictを継承する新しいクラスとしてTypedDictを定義します。このクラスの内部で、キーとそれに対応する型を定義します。

ユーザープロファイルのための単純なTypedDictを作成してみます。

python
from typing import TypedDict

class UserProfile(TypedDict):
    name: str
    age: int
    email: str

上記の例では、UserProfileという名前のTypedDictを作成しました。この定義によれば、UserProfileの型である辞書は、nameageemailというキーを持ち、それぞれの型はstrintstrである必要があります。

UserProfile TypedDictを定義したので、それを使用する方法を見てみます。

python
def display_user(profile: UserProfile) -> None:
    print(f"Name: {profile['name']}")
    print(f"Age: {profile['age']}")
    print(f"Email: {profile['email']}")

user: UserProfile = {
    'name': 'Alice',
    'age': 30,
    'email': 'alice@example.com'
}

display_user(user)

上記のコードでは、まずdisplay_userという関数を定義し、UserProfileの辞書を引数として受け取り、ユーザーの情報を出力します。次に、先ほど定義したUserProfile TypedDictに基づいてユーザー辞書を作成し、display_useruserを引数として呼び出しています。

関数シグネチャの型ヒントにより、display_user関数が常に正しい型の辞書を受け取ることが保証されます。UserProfile TypedDictに準拠しない辞書でdisplay_userを呼び出そうとする場合(例えば、キーが欠けているか、キーの値が間違った型である場合)、タイプエラーが発生します。

TypedDictのオプションキー

前のセクションで作成したTypedDictでは、全てのキーが存在し、特定の型であることが要求されました。しかし、オプションキーを持つTypedDictを定義することも可能です。これは、TypedDictの定義でtotalパラメータを使用することで実現できます。

ユーザープロファイルの中でメールアドレスがオプションの場合を考えてみます。UserProfileの定義においてtotal=Falseと設定することで表現できます。

python
from typing import TypedDict

class UserProfile(TypedDict, total=False):
    name: str
    age: int
    email: str

これにより、UserProfileemailキーを持っていても持っていなくても有効です。

python
def display_user(profile: UserProfile) -> None:
    print(f"Name: {profile['name']}")
    print(f"Age: {profile['age']}")
    if 'email' in profile:
        print(f"Email: {profile['email']}")

user: UserProfile = {
    'name': 'Alice',
    'age': 30
}

display_user(user)

上記のコードでは、display_user関数を修正し、プロファイルにメールアドレスが存在する場合にのみメールアドレスを出力するようにしました。その後、メールアドレスのないユーザープロファイルを作成し、display_user(user_without_email)をエラーなく実行しています。

ネストされたTypedDict

TypedDictは、より複雑なデータ構造を表現するためにネストさせることもできます。ユーザープロファイルに住所情報が含まれるシナリオを考えてみます。住所情報自体がいくつかのフィールドを持つ辞書であるとします。

python
from typing import TypedDict

class Address(TypedDict):
    street: str
    city: str
    state: str
    zip_code: str

class UserProfile(TypedDict):
    name: str
    age: int
    email: str
    address: Address

上記のコードでは、AddressというTypedDictを定義し、それをUserProfileの定義で使用しています。これにより、UserProfileaddressというキーを含み、その値はAddressというTypedDictである必要があります。

TypedDictと継承

TypedDictは継承もサポートしています。これは、複数の種類の辞書がいくつかのフィールドを共有しつつ、独自の固有のフィールドを持っている場合に便利です。

例えば、ユーザープロファイルだけでなく管理者プロファイルも持っている場合を考えてみます。管理者はユーザーと同じフィールドを全て持っていますが、追加でpermissionsフィールドを持っています。

python
class AdminProfile(UserProfile):
    permissions: list[str]

上記のコードでは、AdminProfileUserProfileのサブクラスとして定義し、追加のpermissionsフィールドを追加しています。これにより、AdminProfileUserProfileの全てのフィールドとpermissionsフィールドを持つことが期待されます。

参考

https://peps.python.org/pep-0589/

Ryusei Kakujo

researchgatelinkedingithub

Focusing on data science for mobility

Bench Press 100kg!