Programování

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.

12. 10. 2026 · 4 min čtení

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.