TypedDictとは
TypedDictはPython 3.8で導入された機能であり、typingモジュールの一部です。これを使用すると、辞書の型ヒントを指定することができます。予期されるキーとそれに対応する値の型を示すことができます。TypedDictは実行時にこれらの型を強制するものではありません。代わりに、静的な型チェックツールに使用され、コードの可読性と保守性を向上させます。
TypedDictの作成
PythonでTypedDictを作成するのは簡単です。まず、typingモジュールからTypedDictクラスをインポートします。次に、TypedDictを継承する新しいクラスとしてTypedDictを定義します。このクラスの内部で、キーとそれに対応する型を定義します。
ユーザープロファイルのための単純なTypedDictを作成してみます。
from typing import TypedDict
class UserProfile(TypedDict):
name: str
age: int
email: str
上記の例では、UserProfileという名前のTypedDictを作成しました。この定義によれば、UserProfileの型である辞書は、name、age、emailというキーを持ち、それぞれの型はstr、int、strである必要があります。
UserProfile TypedDictを定義したので、それを使用する方法を見てみます。
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_userをuserを引数として呼び出しています。
関数シグネチャの型ヒントにより、display_user関数が常に正しい型の辞書を受け取ることが保証されます。UserProfile TypedDictに準拠しない辞書でdisplay_userを呼び出そうとする場合(例えば、キーが欠けているか、キーの値が間違った型である場合)、タイプエラーが発生します。
TypedDictのオプションキー
前のセクションで作成したTypedDictでは、全てのキーが存在し、特定の型であることが要求されました。しかし、オプションキーを持つTypedDictを定義することも可能です。これは、TypedDictの定義でtotalパラメータを使用することで実現できます。
ユーザープロファイルの中でメールアドレスがオプションの場合を考えてみます。UserProfileの定義においてtotal=Falseと設定することで表現できます。
from typing import TypedDict
class UserProfile(TypedDict, total=False):
name: str
age: int
email: str
これにより、UserProfileはemailキーを持っていても持っていなくても有効です。
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は、より複雑なデータ構造を表現するためにネストさせることもできます。ユーザープロファイルに住所情報が含まれるシナリオを考えてみます。住所情報自体がいくつかのフィールドを持つ辞書であるとします。
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の定義で使用しています。これにより、UserProfileはaddressというキーを含み、その値はAddressというTypedDictである必要があります。
TypedDictと継承
TypedDictは継承もサポートしています。これは、複数の種類の辞書がいくつかのフィールドを共有しつつ、独自の固有のフィールドを持っている場合に便利です。
例えば、ユーザープロファイルだけでなく管理者プロファイルも持っている場合を考えてみます。管理者はユーザーと同じフィールドを全て持っていますが、追加でpermissionsフィールドを持っています。
class AdminProfile(UserProfile):
permissions: list[str]
上記のコードでは、AdminProfileをUserProfileのサブクラスとして定義し、追加のpermissionsフィールドを追加しています。これにより、AdminProfileはUserProfileの全てのフィールドとpermissionsフィールドを持つことが期待されます。
参考