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.
本文总阅读量次