コンテンツにスキップ

パフォーマンスのヒント

ほとんどの場合、Pydantic がボトルネックになることはありません。確実に必要な場合にのみこれに従ってください。

一般に、 model_validate_json()を使用します。 model_validate(json.loads(...))

の上 model_validate(json.loads(...)) 、JSON は Python で解析され、辞書に変換され、内部で検証されます。一方、 model_validate_json()すでに内部で検証を実行しています。

いくつかのケースがありますが、 model_validate(json.loads(...)) より速いかもしれません。具体的には、モデルで'before'バリデーターまたは'wrap'バリデーターを使用する場合、2 ステップの方法を使用すると検証が高速になる可能性があります。これらの特殊なケースについて詳しくは、この説明を参照してください。

ここで説明されているように、 pydantic-coreでは現在、多くのパフォーマンスの改善が行われています。これらの変更がマージされると、 model_validate_json()の方が常に高速になるはずです。 model_validate(json.loads(...))

TypeAdapter一度インスタンス化される

ここでの考え方は、バリデーターとシリアライザーを必要以上に構築しないようにすることです。 TypeAdapterがインスタンス化されるたびに、新しいバリデーターとシリアライザーが構築されます。関数でTypeAdapter使用している場合、関数が呼び出されるたびに TypeAdapter がインスタンス化されます。代わりに、一度インスタンス化して再利用します。

\=== "❌ 悪い"

```py
from typing import List

from pydantic import TypeAdapter


def my_func():
    adapter = TypeAdapter(List[int])
    # do something with adapter
```

\=== "✅ 良好"

```py
from typing import List

from pydantic import TypeAdapter

adapter = TypeAdapter(List[int])

def my_func():
    ...
    # do something with adapter
```

Sequencelistまたはtuple - Mappingdict

Sequenceを使用する場合、Pydantic はisinstance(value, Sequence)を呼び出して、値がシーケンスであるかどうかを確認します。また、Pydantic は、 listtupleなどのさまざまなタイプのシーケンスに対して検証を試みます。値がlistまたはtupleであることがわかっている場合は、 Sequence代わりにlistまたはtuple使用します。

同じことがMappingdictにも当てはまります。値がdictであることがわかっている場合は、 Mappingの代わりにdictを使用します。

必要がない場合は検証を行わないでください - 値を変更しないようにするにはAnyを使用してください

値を検証する必要がない場合は、 Any使用して値を変更しないでください。

from typing import Any

from pydantic import BaseModel


class Model(BaseModel):
    a: Any


model = Model(a=1)

プリミティブのサブクラスによる余分な情報の回避

\=== 「こんなことはしないでください」

```py
class CompletedStr(str):
    def __init__(self, s: str):
        self.s = s
        self.done = False
```

\=== 「これをしてください」

```py
from pydantic import BaseModel


class CompletedModel(BaseModel):
    s: str
    done: bool = False
```

Union ではなくタグ付き Union を使用する

タグ付き共用体 (または判別共用体) は、どの型であるかを示すフィールドを持つ共用体です。

from typing import Any

from typing_extensions import Literal

from pydantic import BaseModel, Field


class DivModel(BaseModel):
    el_type: Literal['div'] = 'div'
    class_name: str | None = None
    children: list[Any] | None = None


class SpanModel(BaseModel):
    el_type: Literal['span'] = 'span'
    class_name: str | None = None
    contents: str | None = None


class ButtonModel(BaseModel):
    el_type: Literal['button'] = 'button'
    class_name: str | None = None
    contents: str | None = None


class InputModel(BaseModel):
    el_type: Literal['input'] = 'input'
    class_name: str | None = None
    value: str | None = None


class Html(BaseModel):
    contents: DivModel | SpanModel | ButtonModel | InputModel = Field(
        discriminator='el_type'
    )

詳細については、 「差別的な結合」を参照してください。

入れ子になったモデルに対してTypedDict使用する

ネストされたモデルを使用する代わりに、 TypedDict使用してデータの構造を定義します。

??? info "パフォーマンスの比較" 単純なベンチマークでは、 TypedDictネストされたモデルより約 2.5 倍高速です。

```py
from timeit import timeit

from typing_extensions import TypedDict

from pydantic import BaseModel, TypeAdapter


class A(TypedDict):
    a: str
    b: int


class TypedModel(TypedDict):
    a: A


class B(BaseModel):
    a: str
    b: int


class Model(BaseModel):
    b: B


ta = TypeAdapter(TypedModel)
result1 = timeit(
    lambda: ta.validate_python({'a': {'a': 'a', 'b': 2}}), number=10000
)
result2 = timeit(
    lambda: Model.model_validate({'b': {'a': 'a', 'b': 2}}), number=10000
)
print(result2 / result1)
```

パフォーマンスを本当に重視する場合は、バリデータのラップを避けてください

ラップバリデーターは通常、他のバリデーターよりも遅くなります。これは、検証中にデータが Python で実体化されることが必要なためです。ラップバリデーターは、複雑な検証ロジックには非常に役立ちますが、最高のパフォーマンスを求める場合は、ラップバリデーターを回避する必要があります。

FailFastによる早期失敗

v2.8 以降では、シーケンス内の項目が検証に失敗した場合に早期に失敗するように、 FailFastアノテーションをシーケンス タイプに適用できます。このアノテーションを使用すると、シーケンス内の項目の 1 つが失敗しても、残りの項目で検証エラーが発生しないため、事実上、可視性とパフォーマンスをトレードオフすることになります。

from typing import List

from typing_extensions import Annotated

from pydantic import FailFast, TypeAdapter, ValidationError

ta = TypeAdapter(Annotated[List[bool], FailFast()])
try:
    ta.validate_python([True, 'invalid', False, 'also invalid'])
except ValidationError as exc:
    print(exc)
    """
    1 validation error for list[bool]
    1
      Input should be a valid boolean, unable to interpret input [type=bool_parsing, input_value='invalid', input_type=str]
    """

FailFast詳細については、こちら をご覧ください。


本文总阅读量