見出し画像

Pydantic V2: 詳細スターターガイド

  • Pydantic V2は、Pythonの型アノテーションを活用して堅牢なデータ検証と設定管理を提供する新しいライブラリで、V1から性能向上とメモリ使用量の削減を実現している。

  • 基本的なモデル定義から、バリデーション処理、シリアライゼーション、カスタムバリデーター作成まで、包括的なデータ処理機能を提供している。

  • ネストされたモデルの構築やカスタムシリアライザーの実装など高度な機能をサポートしており、特にAPI、データベース、ユーザー入力などの外部データを扱うPythonアプリケーションで効果的に活用できる。


Pydanticは、Pythonの型アノテーションを使用してデータ検証と設定管理を提供する強力なPythonライブラリである。Pydantic V2のリリースにより、複数の機能強化と新機能が導入され、データ検証がより効率的で直感的になった。

この詳細なスターターガイドでは、Pydantic V2の核となる機能を探求し、以下のようなトピックを取り上げる:

  • 基本的なモデルの作成

  • バリデーション例外の処理

  • データのデシリアライズ

  • 必須フィールドとオプショナルフィールドの取り扱い

  • エイリアスと`Field`クラスの使用

  • シリアライゼーション技法

  • 可変デフォルト値とデフォルトファクトリの管理

  • カスタムシリアライザーとバリデーター

  • ネストされたモデルの構築

Pydanticを初めて使用する場合でも、V1からアップグレードする場合でも、このガイドはPydantic V2の機能を理解し活用するのに役立つだろう。


Pydantic V2の紹介

Pydanticは、Pythonの型ヒントを使用してデータを検証および解析するデータ解析・検証ライブラリである。これは、データが指定された型に準拠していることを保証し、特にAPI、データベース、またはユーザー入力のような外部データソースを扱う際に、Pythonアプリケーションにおけるデータ検証の不可欠なツールとなっている。

Pydantic V2の新機能は?

Pydantic V2は、V1から以下のような複数の改善を導入している:

  • パフォーマンスの向上とメモリ使用量の削減

  • エラーメッセージとバリデーション例外の改善

  • カスタムシリアライザーとバリデーターのサポート

  • Pythonの型ヒントシステムとのより良い統合


インストール

Pydantic V2を使い始めるには、pipを使用してインストールできる:

pip install pydantic

Pydantic V2は最新のPythonの機能を活用しているため、Python 3.7以上が必要である。


基本的なモデル

Pydanticの中核となるのはモデルであり、これは`BaseModel`を継承するPythonクラスである。これらのモデルは型アノテーションを使用してデータの構造を定義する。

例:シンプルなモデルの作成

from pydantic import BaseModel

class Person(BaseModel):
    first_name: str
    last_name: str
    age: int

この例では:

  • `pydantic`から`BaseModel`をインポートしている

  • `BaseModel`を継承する`Person`クラスを定義している

  • `first_name`、`last_name`、`age`という3つのフィールドをそれぞれの型と共に宣言している

モデルのインスタンス化

必要なデータを渡してモデルのインスタンスを作成できる:

person = Person(first_name="John", last_name="Doe", age=30)
print(person)

出力:

first_name='John' last_name='Doe' age=30

Pydanticは提供されたデータが指定された型と一致することを保証する。

型の検証と変換

Pydanticは可能な場合、入力データを指定された型に変換を試みる。例えば、`age`フィールドに整数の文字列表現を渡した場合:

person = Person(first_name="Jane", last_name="Doe", age="25")
print(person.age)

出力:

25

`age`フィールドは正しく整数として解析される。


バリデーション例外

データが指定された型に変換できない場合、Pydanticは`ValidationError`を発生させる。

例:バリデーションエラーの処理

from pydantic import ValidationError

try:
    person = Person(first_name="Alice", last_name="Smith", age="twenty-five")
except ValidationError as e:
    print(e)

出力:

1 validation error for Person
age
  value is not a valid integer (type=type_error.integer)

Pydanticは、どのフィールドが検証に失敗し、その理由を示す詳細なエラーメッセージを提供する。

エラー詳細へのアクセス

エラーをデータとしてアクセスできる:

errors = e.errors()
print(errors)

出力:

[
    {
        'loc': ('age',),
        'msg': 'value is not a valid integer',
        'type': 'type_error.integer'
    }
]

データのデシリアライズ

Pydanticモデルは辞書またはJSON文字列からインスタンス化できる。

辞書からの変換

data = {'first_name': 'Bob', 'last_name': 'Brown', 'age': 40}
person = Person.model_validate(data)
print(person)

JSON文字列からの変換

json_data = '{"first_name": "Eve", "last_name": "White", "age": 28}'
person = Person.model_validate_json(json_data)
print(person)

必須フィールドとオプショナルフィールド

デフォルトでは、デフォルト値が提供されない限り、Pydanticモデルのすべてのフィールドは必須である。

デフォルト値を持つオプショナルフィールド

class Employee(BaseModel):
    first_name: str
    last_name: str
    middle_name: str = ''  # オプショナルフィールドでデフォルト値あり

これで、`middle_name`はオプショナルになる:

employee = Employee(first_name="John", last_name="Doe")
print(employee)

出力:

first_name='John' last_name='Doe' middle_name=''

Null許容フィールド

フィールドが`None`を有効な値として受け入れるようにするには、型アノテーションに`None`を含める必要がある。

Union型の使用(Python 3.10以上)

class User(BaseModel):
    username: str
    email: str | None  # emailはNoneを許容する

`Union`の使用(Python 3.9以前)

from typing import Union

class User(BaseModel):
    username: str
    email: Union[str, None]  # emailはNoneを許容する

`Optional`の使用

from typing import Optional

class User(BaseModel):
    username: str
    email: Optional[str]  # emailはNoneを許容する

エイリアスと`Field`クラス

データソースのフィールド名がモデルのフィールド名と一致しない場合がある。エイリアスを使用してそれらをマッピングできる。

例:エイリアスの使用

from pydantic import Field

class Product(BaseModel):
    product_id: int = Field(alias='id')
    name: str = Field(alias='productName')
    price: float

データを検証する際:

data = {'id': 100, 'productName': 'Laptop', 'price': 999.99}
product = Product.model_validate(data)
print(product)

出力:

product_id=100 name='Laptop' price=999.99

エイリアスを持つフィールドへのアクセス

シリアライズ時に、エイリアスを使用するかどうかを選択できる:

print(product.model_dump())

出力:

{'product_id': 100, 'name': 'Laptop', 'price': 999.99}
print(product.model_dump(by_alias=True))

出力:

{'id': 100, 'productName': 'Laptop', 'price': 999.99}

シリアライゼーション

Pydanticモデルは辞書またはJSONにシリアライズできる。

辞書へのシリアライズ

data_dict = person.model_dump()
print(data_dict)

出力:

{'first_name': 'Eve', 'last_name': 'White', 'age': 28}

JSONへのシリアライズ

json_str = person.model_dump_json()
print(json_str)

出力:

{"first_name": "Eve", "last_name": "White", "age": 28}

フィールドのデフォルト値

`Field`クラスを使用する際、`default`パラメータを使用してデフォルト値を設定できる。

class Settings(BaseModel):
    environment: str = Field(default='production', alias='env')
    debug: bool = False

モデル設定:名前による投入

デフォルトでは、エイリアスを使用する場合、Pydanticはエイリアスを使用してデータが提供されることを期待する。フィールド名による投入を許可するには、モデルの設定を調整できる。

`populate_by_name`の有効化

from pydantic import ConfigDict

class ConfiguredProduct(BaseModel):
    model_config = ConfigDict(populate_by_name=True)
    product_id: int = Field(alias='id')
    name: str = Field(alias='productName')
    price: float

これで、データを提供する際にフィールド名またはエイリアスのいずれかを使用できる:

product = ConfiguredProduct(product_id=101, name='Tablet', price=499.99)
print(product)

出力:

product_id=101 name='Tablet' price=499.99

可変デフォルト値

Pythonでは、可変なデフォルト引数を使用すると予期しない動作につながる可能性がある。Pydanticは、各インスタンスに対して可変なデフォルト値のディープコピーを作成することでこれを処理する。

class Basket(BaseModel):
    items: list[str] = []

basket1 = Basket()
basket2 = Basket()

basket1.items.append('Apple')
print(basket1.items)  # ['Apple']
print(basket2.items)  # []

各インスタンスは独自の別個の`items`リストを持つ。


デフォルトファクトリ

動的なデフォルト値(例:現在のタイムスタンプ)が必要な場合、デフォルトファクトリを使用できる。

例:`default_factory`の使用

from datetime import datetime

class Event(BaseModel):
    timestamp: datetime = Field(default_factory=datetime.utcnow)
    event_name: str

event = Event(event_name='UserSignup')
print(event)

出力:

timestamp=datetime.datetime(2024, 11, 10, 14, 30, 45, 123456) event_name='UserSignup'

カスタムシリアライザー

フィールドのシリアライズ方法をカスタマイズできる。

例:浮動小数点数のカスタムシリアライザー

from pydantic import field_serializer

class Measurement(BaseModel):
    value: float

    @field_serializer('value')
    def round_value(self, value):
        return round(value, 2)

measurement = Measurement(value=3.14159)
print(measurement.model_dump())

出力:

{'value': 3.14}

カスタムバリデーター

カスタムバリデーターを使用することで、追加の検証ロジックを強制できる。

例:リスト内の要素の一意性を強制する

from pydantic import field_validator

class UniqueList(BaseModel):
    items: list[int]

    @field_validator('items')
    @classmethod
    def check_unique(cls, items):
        if len(items) != len(set(items)):
            raise ValueError('Items must be unique')
        return items

try:
    unique_list = UniqueList(items=[1, 2, 2, 3])
except ValidationError as e:
    print(e)

出力:

1 validation error for UniqueList
items
  Items must be unique (type=value_error)

ネストされたモデル

Pydanticモデルは他のモデルをフィールドとして含むことができ、複雑なデータ構造を表現することができる。

例:ネストされたモデル

class Address(BaseModel):
    street: str
    city: str
    zip_code: str

class User(BaseModel):
    username: str
    address: Address

data = {
    'username': 'johndoe',
    'address': {
        'street': '123 Main St',
        'city': 'Anytown',
        'zip_code': '12345'
    }
}

user = User.model_validate(data)
print(user)

出力:

username='johndoe' address=Address(street='123 Main St', city='Anytown', zip_code='12345')

結論

Pydantic V2は、型アノテーションの力を活用して、Pythonアプリケーションに堅牢なデータ検証と解析機能をもたらす。データ構造を反映したモデルを定義することで、データの整合性を確保し、アプリケーションのエラーを削減することができる。

このガイドでは、モデルの作成、検証の処理、フィールドの操作、カスタムシリアライザーやネストされたモデルなどの高度な機能の利用など、Pydantic V2の基礎的な側面を取り上げた。

重要なポイント:

  • 型アノテーション: Pythonの型ヒントを使用してモデルフィールドを定義する

  • バリデーション: Pydanticは自動的にデータ型を検証し変換する

  • デシリアライゼーション: モデルは辞書やJSON文字列からインスタンス化できる

  • シリアライゼーション: モデルは辞書やJSONに再度シリアライズできる

  • カスタマイズ: カスタムシリアライザーとバリデーターを利用して高度な制御が可能

  • ネストされたモデル: ネストされたモデルで複雑なデータ構造を構築できる

プロジェクトにPydanticを組み込むことで、より明確で保守性の高いコードを実現し、アプリケーション全体のデータ処理を改善することができる。


さらなる学習

Happy coding!


「超本当にドラゴン」へ

この記事が気に入ったらサポートをしてみませんか?