Warum Pydantic verwenden?¶
Heute wird Pydantic mehrmals im Monat heruntergeladen und von einigen der größten und bekanntesten Organisationen der Welt verwendet.
Es ist schwer zu sagen, warum so viele Menschen Pydantic seit seiner Einführung vor sechs Jahren übernommen haben, aber hier sind ein paar Vermutungen.
Typhinweise zur Unterstützung der Schemavalidierung¶
Das Schema, anhand dessen Pydantic validiert, wird im Allgemeinen durch Hinweise vom Typ Python definiert.
Typhinweise eignen sich hierfür hervorragend, da Sie, wenn Sie modernes Python schreiben, bereits wissen, wie man sie verwendet. Die Verwendung von Typhinweisen bedeutet auch, dass sich Pydantic gut in statische Typisierungstools wie mypy und pyright sowie IDEs wie pycharm und vscode integrieren lässt.
???+ Beispiel „Beispiel – einfach Hinweise eingeben“ (Für dieses Beispiel ist Python 3.9+ erforderlich) ```py erfordert="3.9" aus der Eingabe von Import Annotated, Dict, List, Literal, Tuple
from annotated_types import Gt
from pydantic import BaseModel
class Fruit(BaseModel):
name: str # (1)!
color: Literal['red', 'green'] # (2)!
weight: Annotated[float, Gt(0)] # (3)!
bazam: Dict[str, List[Tuple[int, bool, float]]] # (4)!
print(
Fruit(
name='Apple',
color='red',
weight=4.2,
bazam={'foobar': [(1, True, 0.1)]},
)
)
#> name='Apple' color='red' weight=4.2 bazam={'foobar': [(1, True, 0.1)]}
```
1. The `name` field is simply annotated with `str` - any string is allowed.
2. The [`Literal`](https://docs.python.org/3/library/typing.html#typing.Literal) type is used to enforce that `color` is either `'red'` or `'green'`.
3. Even when we want to apply constraints not encapsulated in python types, we can use [`Annotated`](https://docs.python.org/3/library/typing.html#typing.Annotated) and [`annotated-types`](https://github.com/annotated-types/annotated-types) to enforce constraints without breaking type hints.
4. I'm not claiming "bazam" is really an attribute of fruit, but rather to show that arbitrarily complex types can easily be validated.
!!! Tipp „Weitere Informationen“ Weitere Informationen finden Sie in der Dokumentation zu den unterstützten Typen.
Leistung¶
Die Kernvalidierungslogik von Pydantic ist in einem separaten Paket pydantic-core implementiert, wobei die Validierung für die meisten Typen in Rust implementiert ist.
Damit gehört Pydantic zu den schnellsten Datenvalidierungsbibliotheken für Python.
??? Beispiel „Leistungsbeispiel – Pydantic vs. dedizierter Code“ Im Allgemeinen sollte dedizierter Code viel schneller sein als ein Allzweck-Validator, aber in diesem Beispiel ist Pydantic beim Parsen von JSON und der Validierung von URLs >300 % schneller als dedizierter Code.
```py title="Performance Example"
import json
import timeit
from urllib.parse import urlparse
import requests
from pydantic import HttpUrl, TypeAdapter
reps = 7
number = 100
r = requests.get('https://api.github.com/emojis')
r.raise_for_status()
emojis_json = r.content
def emojis_pure_python(raw_data):
data = json.loads(raw_data)
output = {}
for key, value in data.items():
assert isinstance(key, str)
url = urlparse(value)
assert url.scheme in ('https', 'http')
output[key] = url
emojis_pure_python_times = timeit.repeat(
'emojis_pure_python(emojis_json)',
globals={
'emojis_pure_python': emojis_pure_python,
'emojis_json': emojis_json,
},
repeat=reps,
number=number,
)
print(f'pure python: {min(emojis_pure_python_times) / number * 1000:0.2f}ms')
#> pure python: 5.32ms
type_adapter = TypeAdapter(dict[str, HttpUrl])
emojis_pydantic_times = timeit.repeat(
'type_adapter.validate_json(emojis_json)',
globals={
'type_adapter': type_adapter,
'HttpUrl': HttpUrl,
'emojis_json': emojis_json,
},
repeat=reps,
number=number,
)
print(f'pydantic: {min(emojis_pydantic_times) / number * 1000:0.2f}ms')
#> pydantic: 1.54ms
print(
f'Pydantic {min(emojis_pure_python_times) / min(emojis_pydantic_times):0.2f}x faster'
)
#> Pydantic 3.45x faster
```
Im Gegensatz zu anderen leistungsorientierten Bibliotheken, die in kompilierten Sprachen geschrieben sind, bietet Pydantic auch eine hervorragende Unterstützung für die Anpassung der Validierung über funktionale Validatoren.
!!! Tipp „Mehr erfahren“ Samuel Colvins Vortrag auf der PyCon 2023 erklärt, wie Pydantic-Core funktioniert und wie es in Pydantic integriert wird.
Serialisierung¶
Pydantic bietet Funktionen zum Serialisieren von Modellen auf drei Arten:
- Zu einem Python-Dikt, das aus den zugehörigen Python-Objekten besteht
- Zu einem Python-Dikt, das nur aus „jsonable“-Typen besteht
- Zu einer JSON-Zeichenfolge
In allen drei Modi kann die Ausgabe angepasst werden, indem bestimmte Felder, nicht festgelegte Felder, Standardwerte und Keine-Werte ausgeschlossen werden
??? Beispiel „Beispiel – Serialisierung auf 3 Arten“ „py from datetime import datetime
from pydantic import BaseModel
class Meeting(BaseModel):
when: datetime
where: bytes
why: str = 'No idea'
m = Meeting(when='2020-01-01T12:00', where='home')
print(m.model_dump(exclude_unset=True))
#> {'when': datetime.datetime(2020, 1, 1, 12, 0), 'where': b'home'}
print(m.model_dump(exclude={'where'}, mode='json'))
#> {'when': '2020-01-01T12:00:00', 'why': 'No idea'}
print(m.model_dump_json(exclude_defaults=True))
#> {"when":"2020-01-01T12:00:00","where":"home"}
```
!!! Tipp „Weitere Informationen“ Sehen Sie sich die Dokumentation zur Serialisierung an.
JSON-Schema¶
JSON-Schema kann für jedes Pydantic-Schema generiert werden – was selbstdokumentierende APIs und die Integration mit einer Vielzahl von Tools ermöglicht, die JSON-Schema unterstützen.
??? Beispiel „Beispiel – JSON-Schema“ „py from datetime import datetime
from pydantic import BaseModel Klassenadresse (BaseModel): Straße: str Stadt: str Postleitzahl: str Klassentreffen (Basismodell): Wann: Datum/Uhrzeit wo: Adresse Warum: str = 'Keine Ahnung' print(Meeting.model_json_schema()) „““ { ' $defs': { 'Adresse': { 'Eigenschaften': { 'street': {'title': 'Street', 'type': 'string'}, 'city': {'title': 'City', 'type': 'string'}, 'zipcode': {'title': 'Zipcode', 'type': 'string'}, }, 'erforderlich': ['Straße', 'Stadt', 'Postleitzahl'], 'title': 'Adresse', 'Typ': 'Objekt', } }, 'Eigenschaften': { 'when': {'format': 'date-time', 'title': 'When', 'type': 'string'}, 'where': {'$ ref': '#/$defs/Address'}, 'why': {'default': 'Keine Ahnung', 'title': 'Why', 'type': 'string'}, }, 'erforderlich': ['wann', 'wo'], 'title': 'Treffen', 'Typ': 'Objekt', } „““ ```
Pydantic generiert JSON Schema Version 2020-12, die neueste Version des Standards, die mit OpenAPI 3.1 kompatibel ist.
!!! Tipp „Weitere Informationen“ Weitere Informationen finden Sie in der Dokumentation zum JSON-Schema.
Strikter Modus und Datenzwang¶
Standardmäßig ist Pydantic tolerant gegenüber häufigen falschen Typen und zwingt Daten in den richtigen Typ – z. B. wird eine an ein Int-Feld übergebene numerische Zeichenfolge als Int geparst.
Pydantic verfügt außerdem über den strict=True-Modus – auch bekannt als „Strict-Modus“ –, in dem Typen nicht erzwungen werden und ein Validierungsfehler ausgelöst wird, es sei denn, die Eingabedaten stimmen genau mit dem Schema oder dem Typhinweis überein.
Der strikte Modus wäre jedoch bei der Validierung von JSON-Daten ziemlich nutzlos, da JSON keine Typen hat, die mit vielen gängigen Python-Typen wie Datum/Uhrzeit, UUID oder Bytes übereinstimmen.
Um dieses Problem zu lösen, kann Pydantic JSON in einem Schritt analysieren und validieren. Dies ermöglicht die Konvertierung sinnvoller Daten wie RFC3339-Zeichenfolgen (auch bekannt als ISO8601) in Datums-/Uhrzeitobjekte. Da das JSON-Parsing in Rust implementiert ist, ist es auch sehr performant.
??? Beispiel „Beispiel – Strikter Modus, der tatsächlich nützlich ist“ ```py from datetime import datetime
from pydantic import BaseModel, ValidationError
class Meeting(BaseModel):
when: datetime
where: bytes
m = Meeting.model_validate({'when': '2020-01-01T12:00', 'where': 'home'})
print(m)
#> when=datetime.datetime(2020, 1, 1, 12, 0) where=b'home'
try:
m = Meeting.model_validate(
{'when': '2020-01-01T12:00', 'where': 'home'}, strict=True
)
except ValidationError as e:
print(e)
"""
2 validation errors for Meeting
when
Input should be a valid datetime [type=datetime_type, input_value='2020-01-01T12:00', input_type=str]
where
Input should be a valid bytes [type=bytes_type, input_value='home', input_type=str]
"""
m_json = Meeting.model_validate_json(
'{"when": "2020-01-01T12:00", "where": "home"}'
)
print(m_json)
#> when=datetime.datetime(2020, 1, 1, 12, 0) where=b'home'
```
!!! Tipp „Weitere Informationen“ Weitere Informationen finden Sie in der Dokumentation zum strikten Modus.
Datenklassen, TypedDicts und mehr¶
Pydantic bietet vier Möglichkeiten, Schemata zu erstellen und Validierung und Serialisierung durchzuführen:
- BaseModel – Pydantics eigene Superklasse mit vielen allgemeinen Dienstprogrammen, die über Instanzmethoden verfügbar sind.
pydantic.dataclasses.dataclass
– ein Wrapper für Standarddatenklassen, der bei der Initialisierung einer Datenklasse eine Validierung durchführt.- TypeAdapter – eine allgemeine Möglichkeit, jeden Typ für die Validierung und Serialisierung anzupassen. Dadurch können Typen wie TypedDict und NamedTuple sowie einfache Skalarwerte wie int oder timedelta validiert werden – alle unterstützten Typen können mit TypeAdapter verwendet werden.
- validate_call – ein Dekorator, der beim Aufruf einer Funktion eine Validierung durchführt.
??? Beispiel „Beispiel – Schema basierend auf TypedDict“ „py from datetime import datetime
from typing_extensions import NotRequired, TypedDict
from pydantic import TypeAdapter
class Meeting(TypedDict):
when: datetime
where: bytes
why: NotRequired[str]
meeting_adapter = TypeAdapter(Meeting)
m = meeting_adapter.validate_python( # (1)!
{'when': '2020-01-01T12:00', 'where': 'home'}
)
print(m)
#> {'when': datetime.datetime(2020, 1, 1, 12, 0), 'where': b'home'}
meeting_adapter.dump_python(m, exclude={'where'}) # (2)!
print(meeting_adapter.json_schema()) # (3)!
"""
{
'properties': {
'when': {'format': 'date-time', 'title': 'When', 'type': 'string'},
'where': {'format': 'binary', 'title': 'Where', 'type': 'string'},
'why': {'title': 'Why', 'type': 'string'},
},
'required': ['when', 'where'],
'title': 'Meeting',
'type': 'object',
}
"""
```
1. `TypeAdapter` for a `TypedDict` performing validation, it can also validate JSON data directly with `validate_json`
2. `dump_python` to serialise a `TypedDict` to a python object, it can also serialise to JSON with `dump_json`
3. `TypeAdapter` can also generate JSON Schema
Anpassung¶
Funktionale Validatoren und Serialisierer sowie ein leistungsstarkes Protokoll für benutzerdefinierte Typen ermöglichen eine individuelle Anpassung der Funktionsweise von Pydantic für jedes Feld oder jeden Typ.
??? Beispiel „Anpassungsbeispiel – Wrap-Validatoren“ „Wrap-Validatoren“ sind neu in Pydantic V2 und eine der leistungsstärksten Möglichkeiten, die Pydantic-Validierung anzupassen. „py from datetime import datetime, timezone.“
from pydantic import BaseModel, field_validator
class Meeting(BaseModel):
when: datetime
@field_validator('when', mode='wrap')
def when_now(cls, input_value, handler):
if input_value == 'now':
return datetime.now()
when = handler(input_value)
# in this specific application we know tz naive datetimes are in UTC
if when.tzinfo is None:
when = when.replace(tzinfo=timezone.utc)
return when
print(Meeting(when='2020-01-01T12:00+01:00'))
#> when=datetime.datetime(2020, 1, 1, 12, 0, tzinfo=TzInfo(+01:00))
print(Meeting(when='now'))
#> when=datetime.datetime(2032, 1, 2, 3, 4, 5, 6)
print(Meeting(when='2020-01-01T12:00'))
#> when=datetime.datetime(2020, 1, 1, 12, 0, tzinfo=datetime.timezone.utc)
```
!!! Tipp „Weitere Informationen“ Sehen Sie sich die Dokumentation zu Validatoren, benutzerdefinierten Serialisierern und benutzerdefinierten Typen an.
Ökosystem¶
Zum Zeitpunkt des Schreibens gibt es 214.100 Repositories auf GitHub und 8.119 Pakete auf PyPI, die von Pydantic abhängen.
Einige bemerkenswerte Bibliotheken, die von Pydantic abhängen:
Weitere Bibliotheken, die Pydantic verwenden, finden Sie unter Kludex/awesome-pydantic.
Organisationen, die Pydantic verwenden¶
Einige namhafte Unternehmen und Organisationen, die Pydantic verwenden, zusammen mit Kommentaren dazu, warum/woher wir wissen, dass sie Pydantic verwenden.
Die folgenden Organisationen sind enthalten, weil sie eines oder mehrere der folgenden Kriterien erfüllen:
- Verwendung von Pydantic als Abhängigkeit in einem öffentlichen Repository
- Verweisender Datenverkehr auf die Pydantic-Dokumentationsseite von einer organisationsinternen Domäne – spezifische Verweise werden nicht berücksichtigt, da sie sich im Allgemeinen nicht in der öffentlichen Domäne befinden
- Direkte Kommunikation zwischen dem Pydantic-Team und den von der Organisation beschäftigten Ingenieuren über die Nutzung von Pydantic innerhalb der Organisation
Wir haben gegebenenfalls einige zusätzliche Details eingefügt, die bereits öffentlich zugänglich sind.
{{ organisations }}
本文总阅读量次