はじめに
Pythonは動的な型付けであるため,変数の型が保証されていない。型ヒントによる宣言やmypy
によるチェックは可能だが実行時の制限はない。
そこで,pydantic
による型に堅牢な書き方を記録する。
TL;DR
-
pydantic
を使用すると簡単に型検証が行える-
pydantic.BaseModel
の継承と型ヒント
-
- 型の宣言は
typing
などによる型ヒントで行う
pydanticとは
下記は公式ドキュメントによる説明です。
- Data validation and settings management using Python type annotations.
- pydantic enforces type hints at runtime, and provides user friendly errors when data is invalid.
- Define how data should be in pure, canonical Python; validate it with pydantic.
-
google 翻訳
- Pythonの型アノテーションを使ったデータ検証・設定管理
- pydanticは実行時に型ヒントを強制し,データが無効な場合はユーザーフレンドリーなエラーを提供
- データがどのようにあるべきかを純粋で標準的なPythonで定義,検証
インストール
pydantic
はpythonの標準モジュールではないので下記コマンドによるインストールが必要
pip install pydantic
使用方法
バージョンは以下のとおり
- Python: 3.10.5
- Pydantic: 1.10.2
以下サンプルコードはimport pydantic
されている前提
基本 pydantic.BaseModel
pydanticのBaseModelを継承して使用する。また,型宣言は型ヒントにより記述する。
型宣言に対して不整合な値が入力された場合はエラーが発生する。しかし,宣言と異なる型の値でもキャストが可能な場合はキャストして代入される。厳密な型検証を行いたい場合は次項を参照
class User(pydantic.BaseModel):
id_: int
name: str
print(f'{User(id_=100, name="abc") = }')
print(f'{User(id_=100.0, name="abc") = }')
print(f'{User(id_="100", name="abc") = }')
try:
User(id_="abc", name="abc")
except pydantic.ValidationError as e:
print("User(id_='abc', name='abc') = ")
print(f"{type(e).__name__}: {e}")
# User(id_=100, name="abc") = User(id_=100, name='abc')
# User(id_=100.0, name="abc") = User(id_=100, name='abc')
# User(id_="100", name="abc") = User(id_=100, name='abc')
# User(id_='abc', name='abc') =
# ValidationError: 1 validation error for User
# id_
# value is not a valid integer (type=type_error.integer)
bool
を宣言した場合は以下のようにキャストされる。
- False:
False, 0, '0', 'off', 'f', 'false', 'n', 'no'
- True:
True, 1, '1', 'on', 't', 'true', 'y', 'yes'
class BooleanModel(pydantic.BaseModel):
is_enabled: bool
print(f'{BooleanModel(is_enabled="on") = }')
print(f'{BooleanModel(is_enabled="off") = }')
try:
BooleanModel(is_enabled=-1)
except pydantic.ValidationError as e:
print("BooleanModel(is_enabled=-1) = ")
print(f"{type(e).__name__}: {e}")
# BooleanModel(is_enabled="on") = BooleanModel(is_enabled=True)
# BooleanModel(is_enabled="off") = BooleanModel(is_enabled=False)
# BooleanModel(is_enabled=-1) =
# ValidationError: 1 validation error for BooleanModel
# is_enabled
# value could not be parsed to a boolean (type=type_error.bool)
初期値と必須項目
初期値を設定することが可能であり,その場合は必須項目ではなくなる。初期値を設定する場合は型宣言を行わなくとも初期値から型が推定される。
class UserWithNumber(pydantic.BaseModel):
id_: int
name: str = "abc"
number = 0
print(f"{UserWithNumber(id_=100) = }")
try:
UserWithNumber()
except pydantic.ValidationError as e:
print("UserWithNumber() = ")
print(f"{type(e).__name__}: {e}")
try:
UserWithNumber(id_=100, number="abc")
except pydantic.ValidationError as e:
print("UserWithNumber(id_=100, number='abc') = ")
print(f"{type(e).__name__}: {e}")
# UserWithNumber(id_=100) = UserWithNumber(id_=100, name='abc', number=0)
# UserWithNumber() =
# ValidationError: 1 validation error for UserWithNumber
# id_
# field required (type=value_error.missing)
# UserWithNumber(id_=100, number='abc') =
# ValidationError: 1 validation error for UserWithNumber
# number
# value is not a valid integer (type=type_error.integer)
複数の型宣言とNull許容
型宣言には複数の型を宣言することが可能。その場合は左の型から優先される。
None
を合わせて宣言することでNullを許容することができる。(新しいバージョンでは初期値とNull許容は別になる予定)
class NullableModel(pydantic.BaseModel):
id_: int | None
name: str
print(f'{NullableModel(id_=100, name="abc") = }')
print(f'{NullableModel(id_=None, name="abc") = }')
print(f'{NullableModel(name="abc") = }')
try:
NullableModel(name=None)
except pydantic.ValidationError as e:
print("NullableModel(name=None) = ")
print(f"{type(e).__name__}: {e}")
# NullableModel(id_=100, name="abc") = NullableModel(id_=100, name='abc')
# NullableModel(id_=None, name="abc") = NullableModel(id_=None, name='abc')
# NullableModel(name="abc") = NullableModel(id_=None, name='abc')
# NullableModel(name=None) =
# ValidationError: 1 validation error for NullableModel
# name
# none is not an allowed value (type=type_error.none.not_allowed)
厳密な型検証
型検証では宣言された型にキャストされる。そのため,int型にfloat値を入力すると小数点以下は切り捨てられる。
厳密に型を検証したい場合はpydantic.StrictInt
やpydantic.StrictBool
などの厳密な型を指定する。(新しいバージョンでは Strict Mode が導入される予定)
class StrictIntModel(pydantic.BaseModel):
strict_int: pydantic.StrictInt
try:
StrictIntModel(strict_int=3.14159)
except pydantic.ValidationError as e:
print("StrictIntModel(strict_int=3.14159) = ")
print(f"{type(e).__name__}: {e}")
# StrictIntModel(strict_int=3.14159) =
# ValidationError: 1 validation error for StrictIntModel
# strict_int
# value is not a valid integer (type=type_error.integer)
class StrictBoolModel(pydantic.BaseModel):
strict_bool: pydantic.StrictBool
try:
StrictBoolModel(strict_bool="False")
except pydantic.ValidationError as e:
print("StrictBoolModel(strict_bool='False') = ")
print(f"{type(e).__name__}: {e}")
# StrictBoolModel(strict_bool='False') =
# ValidationError: 1 validation error for StrictBoolModel
# strict_bool
# value is not a valid boolean (type=value_error.strictbool)