Leistungstipps¶
In den meisten Fällen wird Pydantic nicht Ihr Flaschenhals sein. Befolgen Sie dies nur, wenn Sie sicher sind, dass es notwendig ist.
Im Allgemeinen verwenden Sie model_validate_json()
nicht model_validate(json.loads(...))
¶
An model_validate(json.loads(...))
, wird der JSON in Python analysiert, dann in ein Diktat konvertiert und dann intern validiert. Andererseits führt model_validate_json()
die Validierung bereits intern durch.
Es gibt einige Fälle, in denen model_validate(json.loads(...))
kann schneller sein. Insbesondere wenn ein 'before'
oder 'wrap'
-Validator für ein Modell verwendet wird, kann die Validierung mit der zweistufigen Methode schneller sein. Mehr über diese Sonderfälle können Sie in dieser Diskussion lesen.
Viele Leistungsverbesserungen sind derzeit für pydantic-core
in Arbeit, wie hier besprochen. Sobald diese Änderungen zusammengeführt sind, sollten wir an dem Punkt angelangt sein, an dem model_validate_json()
immer schneller ist als model_validate(json.loads(...))
.
TypeAdapter
einmal instanziiert¶
Die Idee dabei ist, die Konstruktion von Validatoren und Serialisierern nicht mehr als nötig zu vermeiden. Jedes Mal, wenn ein TypeAdapter
instanziiert wird, erstellt er einen neuen Validator und Serialisierer. Wenn Sie einen TypeAdapter
in einer Funktion verwenden, wird dieser bei jedem Aufruf der Funktion instanziiert. Instanziieren Sie es stattdessen einmal und verwenden Sie es erneut.
\=== „ Schlecht“
```py
from typing import List
from pydantic import TypeAdapter
def my_func():
adapter = TypeAdapter(List[int])
# do something with adapter
```
\=== " Gut"
```py
from typing import List
from pydantic import TypeAdapter
adapter = TypeAdapter(List[int])
def my_func():
...
# do something with adapter
```
Sequence
vs. list
oder tuple
– Mapping
vs. dict
¶
Bei Verwendung von Sequence
ruft Pydantic isinstance(value, Sequence)
auf, um zu überprüfen, ob der Wert eine Sequenz ist. Außerdem wird Pydantic versuchen, eine Validierung anhand verschiedener Arten von Sequenzen durchzuführen, z. B. list
und tuple
. Wenn Sie wissen, dass der Wert eine list
oder tuple
ist, verwenden Sie list
oder tuple
anstelle von Sequence
.
Das Gleiche gilt für Mapping
und dict
. Wenn Sie wissen, dass der Wert ein dict
ist, verwenden Sie dict
anstelle von Mapping
.
Führen Sie keine Validierung durch, wenn dies nicht erforderlich ist. Verwenden Sie Any
, um den Wert unverändert zu lassen¶
Wenn Sie einen Wert nicht validieren müssen, verwenden Sie Any
, um den Wert unverändert zu lassen.
from typing import Any
from pydantic import BaseModel
class Model(BaseModel):
a: Any
model = Model(a=1)
Vermeiden Sie zusätzliche Informationen über Unterklassen von Grundelementen¶
\=== „Tu das nicht“
```py
class CompletedStr(str):
def __init__(self, s: str):
self.s = s
self.done = False
```
\=== „Mach das“
```py
from pydantic import BaseModel
class CompletedModel(BaseModel):
s: str
done: bool = False
```
Verwenden Sie getaggte Union, nicht Union¶
Eine getaggte Union (oder diskriminierte Union) ist eine Union mit einem Feld, das angibt, um welchen Typ es sich handelt.
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'
)
Weitere Einzelheiten finden Sie unter „Diskriminierte Gewerkschaften“ .
Verwenden Sie TypedDict
für verschachtelte Modelle¶
Anstatt verschachtelte Modelle zu verwenden, verwenden Sie TypedDict
um die Struktur der Daten zu definieren.
??? Info „Leistungsvergleich“ Mit einem einfachen Benchmark ist TypedDict
etwa ~2,5x schneller als verschachtelte Modelle:
```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)
```
Vermeiden Sie Wrap-Validatoren, wenn Ihnen die Leistung wirklich am Herzen liegt¶
Wrap-Validatoren sind im Allgemeinen langsamer als andere Validatoren. Dies liegt daran, dass sie erfordern, dass Daten während der Validierung in Python materialisiert werden. Wrap-Validatoren können für komplexe Validierungslogik unglaublich nützlich sein, aber wenn Sie auf der Suche nach der besten Leistung sind, sollten Sie sie meiden.
Mit FailFast
frühzeitig scheitern¶
Ab Version 2.8+ können Sie die FailFast
-Annotation auf Sequenztypen anwenden, um frühzeitig fehlzuschlagen, wenn ein Element in der Sequenz die Validierung nicht besteht. Wenn Sie diese Annotation verwenden, erhalten Sie keine Validierungsfehler für die restlichen Elemente in der Sequenz, wenn eines davon fehlschlägt, Sie tauschen also effektiv Sichtbarkeit gegen Leistung ein.
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]
"""
Lesen Sie mehr über FailFast
hier.
本文总阅读量次