Dataclasses vs. Pydantic: kdy použít kterou datovou třídu
Srovnání dataclasses a Pydantic v2 – validace, konverze typů, výkon, serializace do JSON a konfigurace z proměnných prostředí. S příklady.
Slovníky jsou pohodlné, dokud nezačnete hledat, jestli se klíč jmenuje user_id, nebo userId. Datové třídy dávají datům pevný tvar, napovídání v editoru a kontrolu typů. V Pythonu máte dvě hlavní možnosti: dataclasses ze standardní knihovny a knihovnu Pydantic. Vypadají podobně, ale řeší jiný problém.
dataclasses: méně psaní, žádná validace
from dataclasses import dataclass, field
@dataclass
class Produkt:
nazev: str
cena: float
stitky: list[str] = field(default_factory=list)
p = Produkt("Hrnek", 149.9)
print(p) # Produkt(nazev='Hrnek', cena=149.9, stitky=[])
p == Produkt("Hrnek", 149.9) # True
Dekorátor vygeneruje __init__, __repr__ a __eq__. Proměnlivé výchozí hodnoty (seznam, slovník) se musí zadávat přes default_factory – jinak dostanete ValueError.
Typy se ale nekontrolují:
Produkt(nazev=123, cena="zdarma") # projde bez chyby
Anotace slouží jen statickým nástrojům (mypy) a editoru.
Užitečné volby
@dataclass(frozen=True, slots=True, kw_only=True)
class Bod:
x: float
y: float
frozen=True– neměnná instance, lze ji použít jako klíč ve slovníku.slots=True(Python 3.10+) – menší paměť a rychlejší přístup k atributům.kw_only=True(3.10+) – argumenty jen pojmenovaně.
Vlastní kontrolu doplníte v __post_init__:
@dataclass
class Produkt:
nazev: str
cena: float
def __post_init__(self):
if self.cena < 0:
raise ValueError("Cena nesmí být záporná")
Pydantic: validace a konverze dat zvenku
pip install pydantic
from pydantic import BaseModel, Field, ValidationError
class Produkt(BaseModel):
nazev: str = Field(min_length=1)
cena: float = Field(ge=0)
stitky: list[str] = []
p = Produkt(nazev="Hrnek", cena="149.9")
print(p.cena, type(p.cena)) # 149.9 <class 'float'>
Pydantic řetězec "149.9" převedl na float (tzv. lax mode). Neplatná data skončí srozumitelnou chybou:
try:
Produkt(nazev="", cena="zdarma")
except ValidationError as e:
print(e)
# 2 validation errors for Produkt
# nazev
# String should have at least 1 character ...
# cena
# Input should be a valid number ...
U Pydanticu je proměnlivá výchozí hodnota [] v pořádku – každá instance dostane vlastní kopii.
JSON dovnitř i ven (Pydantic v2)
data = '{"nazev": "Tričko", "cena": 399, "stitky": ["bavlna"]}'
p = Produkt.model_validate_json(data)
p.model_dump() # dict
p.model_dump_json() # str
Produkt.model_json_schema() # JSON Schema
Pozor: Pydantic v1 používal .dict(), .json() a parse_obj(). Ve v2 jsou to model_dump(), model_dump_json() a model_validate(). Staré názvy jsou označené jako zastaralé.
Vlastní validátor
from pydantic import field_validator
class Uzivatel(BaseModel):
email: str
@field_validator("email")
@classmethod
def normalizuj(cls, v: str) -> str:
if "@" not in v:
raise ValueError("neplatný e-mail")
return v.strip().lower()
Pro skutečnou validaci e-mailu použijte typ EmailStr (vyžaduje pip install "pydantic[email]").
Striktní režim
Pokud nechcete automatické převody:
from pydantic import ConfigDict
class Prisny(BaseModel):
model_config = ConfigDict(strict=True)
pocet: int
Prisny(pocet="5") # ValidationError
Konfigurace z prostředí: pydantic-settings
pip install pydantic-settings
from pydantic_settings import BaseSettings, SettingsConfigDict
class Nastaveni(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", env_prefix="APP_")
database_url: str
debug: bool = False
port: int = 8000
cfg = Nastaveni() # čte APP_DATABASE_URL, APP_DEBUG, APP_PORT
Chybějící povinná proměnná ukončí aplikaci hned při startu, ne až při prvním použití.
Srovnání
| dataclasses | Pydantic v2 | |
|---|---|---|
| Závislost | žádná (stdlib) | externí balíček |
| Kontrola typů za běhu | ne | ano |
| Konverze typů | ne | ano (lze vypnout) |
| JSON serializace | ručně (asdict + json) |
vestavěná |
| Rychlost vytváření instancí | vyšší | nižší (validace něco stojí) |
| JSON Schema | ne | ano |
Jádro Pydanticu v2 je napsané v Rustu, takže validace je rychlá. Pořád je to ale práce navíc oproti prostému přiřazení atributů.
Kdy co použít
Pydantic na hranicích aplikace – tam, kde přicházejí nedůvěryhodná data:
- tělo HTTP požadavku (FastAPI ho používá automaticky),
- odpovědi cizích API,
- konfigurační soubory a proměnné prostředí,
- data z formulářů a uploadů.
dataclasses uvnitř aplikace – data, která už prošla validací nebo je vytváříte sami:
- doménové objekty v business logice,
- návratové hodnoty funkcí s více poli,
- výkonnostně citlivé části s velkým množstvím instancí.
Kombinace je běžná: na vstupu Pydantic model, který se převede na interní dataclass. Pydantic navíc umí validovat i obyčejné dataclasses přes pydantic.dataclasses.dataclass nebo TypeAdapter, pokud potřebujete validaci výjimečně.
Alternativy
- attrs – předchůdce dataclasses s více funkcemi a volitelnými validátory.
- msgspec – velmi rychlá serializace a validace, vhodná pro výkonné služby.
- TypedDict – když data musí zůstat slovníkem, ale chcete typovou kontrolu v mypy.