Lewati ke isi

Kiat kinerja

Dalam kebanyakan kasus, Pydantic tidak akan menjadi penghambat Anda, ikuti saja ini jika Anda yakin itu perlu.

Secara umum, gunakan model_validate_json() tidak model_validate(json.loads(...))

Pada model_validate(json.loads(...)) , JSON diurai dengan Python, lalu diubah menjadi dict, lalu divalidasi secara internal. Di sisi lain, model_validate_json() sudah melakukan validasi secara internal.

Ada beberapa kasus dimana model_validate(json.loads(...)) mungkin lebih cepat. Khususnya, saat menggunakan validator 'before' atau 'wrap' pada suatu model, validasi mungkin lebih cepat dengan metode dua langkah. Anda dapat membaca lebih lanjut tentang kasus-kasus khusus ini dalam diskusi ini .

Banyak peningkatan kinerja yang sedang dikerjakan untuk pydantic-core , seperti yang dibahas di sini . Setelah perubahan ini digabungkan, kita akan berada pada titik di mana model_validate_json() selalu lebih cepat daripada model_validate(json.loads(...)) .

TypeAdapter dipakai satu kali

Idenya di sini adalah untuk menghindari pembuatan validator dan serializer lebih dari yang diperlukan. Setiap kali TypeAdapter dipakai, ia akan membuat validator dan serializer baru. Jika Anda menggunakan TypeAdapter dalam suatu fungsi, itu akan dipakai setiap kali fungsi tersebut dipanggil. Sebaliknya, buat instance-nya sekali, dan gunakan kembali.

\=== "❌ Buruk"

```py
from typing import List

from pydantic import TypeAdapter


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

\=== "✅ Bagus"

```py
from typing import List

from pydantic import TypeAdapter

adapter = TypeAdapter(List[int])

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

Sequence vs list atau tuple - Mapping vs dict

Saat menggunakan Sequence , Pydantic memanggil isinstance(value, Sequence) untuk memeriksa apakah nilainya berurutan. Selain itu, Pydantic akan mencoba memvalidasi terhadap berbagai jenis urutan, seperti list dan tuple . Jika Anda mengetahui nilainya adalah list atau tuple , gunakan list atau tuple alih-alih Sequence .

Hal yang sama berlaku untuk Mapping dan dict . Jika Anda mengetahui nilainya adalah dict , gunakan dict alih-alih Mapping .

Jangan lakukan validasi jika tidak diperlukan - gunakan Any agar nilainya tidak berubah

Jika Anda tidak perlu memvalidasi nilai, gunakan Any agar nilainya tidak berubah.

from typing import Any

from pydantic import BaseModel


class Model(BaseModel):
    a: Any


model = Model(a=1)

Hindari informasi tambahan melalui subkelas primitif

\=== "Jangan lakukan ini"

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

\=== "Lakukan ini"

```py
from pydantic import BaseModel


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

Gunakan serikat yang diberi tag, bukan serikat pekerja

Serikat yang diberi tag (atau serikat yang didiskriminasi) adalah serikat pekerja dengan bidang yang menunjukkan jenisnya.

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'
    )

Lihat Serikat Pekerja yang Didiskriminasi untuk lebih jelasnya.

Gunakan TypedDict pada model bersarang

Daripada menggunakan model bertingkat, gunakan TypedDict untuk menentukan struktur data.

??? info "Perbandingan kinerja" Dengan tolok ukur sederhana, TypedDict sekitar ~2,5x lebih cepat dibandingkan model bersarang:

```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)
```

Hindari membungkus validator jika Anda benar-benar peduli dengan kinerja

Validator bungkus umumnya lebih lambat dibandingkan validator lainnya. Ini karena mereka mengharuskan data diwujudkan dengan Python selama validasi. Validator bungkus bisa sangat berguna untuk logika validasi yang kompleks, namun jika Anda mencari performa terbaik, Anda harus menghindarinya.

Gagal lebih awal dengan FailFast

Mulai v2.8+, Anda dapat menerapkan anotasi FailFast ke tipe urutan agar gagal lebih awal jika ada item dalam urutan yang gagal validasi. Jika Anda menggunakan anotasi ini, Anda tidak akan mendapatkan kesalahan validasi untuk item lainnya dalam urutan jika salah satu item gagal, jadi Anda secara efektif mengorbankan visibilitas demi performa.

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]
    """

Baca selengkapnya tentang FailFast di sini.


本文总阅读量