Prestatietips¶
In de meeste gevallen zal Pydantic niet uw knelpunt zijn, volg dit alleen als u zeker weet dat het nodig is.
Gebruik in het algemeen model_validate_json()
niet model_validate(json.loads(...))
¶
Op model_validate(json.loads(...))
, wordt de JSON geparseerd in Python, vervolgens geconverteerd naar een dictaat en vervolgens intern gevalideerd. Aan de andere kant voert model_validate_json()
de validatie al intern uit.
Er zijn een paar gevallen waarin model_validate(json.loads(...))
kan sneller zijn. Met name als u een 'before'
of 'wrap'
validator op een model gebruikt, kan de validatie sneller verlopen met de tweestapsmethode. In deze discussie leest u meer over deze bijzondere gevallen.
Er zijn momenteel veel prestatieverbeteringen in de maak voor pydantic-core
, zoals hier besproken. Zodra deze wijzigingen zijn samengevoegd, zouden we op het punt moeten zijn waar model_validate_json()
altijd sneller is dan model_validate(json.loads(...))
.
TypeAdapter
eenmaal geïnstantieerd¶
Het idee hier is om te voorkomen dat er meer validators en serializers worden gebouwd dan nodig is. Elke keer dat een TypeAdapter
wordt geïnstantieerd, zal deze een nieuwe validator en serializer construeren. Als u een TypeAdapter
in een functie gebruikt, wordt deze elke keer dat de functie wordt aangeroepen, geïnstantieerd. In plaats daarvan instantiëert u het eenmaal en gebruikt u het opnieuw.
\=== " Slecht"
```py
from typing import List
from pydantic import TypeAdapter
def my_func():
adapter = TypeAdapter(List[int])
# do something with adapter
```
\=== " Goed"
```py
from typing import List
from pydantic import TypeAdapter
adapter = TypeAdapter(List[int])
def my_func():
...
# do something with adapter
```
Sequence
versus list
tuple
- Mapping
versus dict
¶
Wanneer u Sequence
gebruikt, roept Pydantic isinstance(value, Sequence)
aan om te controleren of de waarde een reeks is. Pydantic zal ook proberen te valideren tegen verschillende soorten reeksen, zoals list
en tuple
. Als u weet dat de waarde een list
of tuple
is, gebruikt u list
of tuple
in plaats van Sequence
.
Hetzelfde geldt voor Mapping
en dict
. Als u weet dat de waarde een dict
is, gebruikt u dict
in plaats van Mapping
.
Voer geen validatie uit als dat niet nodig is; gebruik Any
om de waarde ongewijzigd te houden¶
Als u een waarde niet hoeft te valideren, gebruikt u Any
om de waarde ongewijzigd te laten.
from typing import Any
from pydantic import BaseModel
class Model(BaseModel):
a: Any
model = Model(a=1)
Vermijd extra informatie via subklassen van primitieven¶
\=== "Doe dit niet"
```py
class CompletedStr(str):
def __init__(self, s: str):
self.s = s
self.done = False
```
\=== "Doe dit"
```py
from pydantic import BaseModel
class CompletedModel(BaseModel):
s: str
done: bool = False
```
Gebruik de getagde unie, niet de unie¶
Getagde unie (of gediscrimineerde unie) is een unie met een veld dat aangeeft welk type het is.
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'
)
Zie Gediscrimineerde Vakbonden voor meer details.
Gebruik TypedDict
over geneste modellen¶
In plaats van geneste modellen te gebruiken, gebruikt u TypedDict
om de structuur van de gegevens te definiëren.
??? info "Prestatievergelijking" Met een eenvoudige benchmark is TypedDict
ongeveer ~2,5x sneller dan geneste modellen:
```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)
```
Vermijd wrap-validators als u echt om prestaties geeft¶
Wrap-validators zijn over het algemeen langzamer dan andere validators. Dit komt omdat ze vereisen dat gegevens tijdens de validatie in Python worden gematerialiseerd. Wrap-validators kunnen ongelooflijk handig zijn voor complexe validatielogica, maar als u op zoek bent naar de beste prestaties, moet u ze vermijden.
Vroegtijdig falen met FailFast
¶
Vanaf v2.8+ kunt u de FailFast
annotatie toepassen op reekstypen, zodat deze vroegtijdig mislukken als een item in de reeks niet wordt gevalideerd. Als u deze annotatie gebruikt, krijgt u geen validatiefouten voor de rest van de items in de reeks als er één mislukt, zodat u zichtbaarheid effectief inruilt voor prestaties.
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]
"""
Lees hier meer over FailFast
.
本文总阅读量次