Typování v Pythonu a mypy: typové anotace, které chytí chyby
Jak psát typové anotace v Pythonu 3.10+, co znamená Optional, Protocol nebo TypedDict a jak nasadit mypy do projektu postupně, bez zbytečné bolesti.
Python je dynamicky typovaný a typové anotace za běhu nic nekontrolují. Přesto se vyplatí je psát: statický kontrolor jako mypy najde chyby dřív, než kód spustíte, a editor díky nim lépe napovídá. Ukážeme si syntaxi pro moderní Python a rozumné nasazení mypy.
Základní syntaxe
def pozdrav(jmeno: str, opakovani: int = 1) -> str:
return ", ".join([f"Ahoj {jmeno}"] * opakovani)
vek: int = 30
ceny: list[float] = [9.9, 19.9]
sklad: dict[str, int] = {"jablka": 5}
souradnice: tuple[float, float] = (50.08, 14.42)
Od Pythonu 3.9 lze používat vestavěné typy list, dict, tuple přímo v anotacích – typing.List a spol. už nepotřebujete.
None a sjednocení typů
Od Pythonu 3.10 se sjednocení píše svislítkem:
def najdi_uzivatele(uid: int) -> dict[str, str] | None:
...
X | None je totéž jako starší Optional[X]. Mypy pak vynutí kontrolu:
u = najdi_uzivatele(1)
print(u["jmeno"]) # error: Value of type "dict[str, str] | None" is not indexable
if u is not None:
print(u["jmeno"]) # OK – mypy ví, že tu už None není
Tomuto zužování typu podle podmínky se říká narrowing a funguje i s isinstance.
Užitečné typy z modulu typing
from typing import Literal, TypedDict, Protocol, Callable, Any
from collections.abc import Iterable, Sequence
Rezim = Literal["dev", "prod"]
class Konfigurace(TypedDict):
host: str
port: int
debug: bool
class MaNazev(Protocol):
nazev: str
def vypis_nazvy(polozky: Iterable[MaNazev]) -> None:
for p in polozky:
print(p.nazev)
Handler = Callable[[str, int], bool]
- Literal – jen konkrétní hodnoty.
- TypedDict – slovník s pevně danými klíči, typicky JSON z API.
- Protocol – strukturální typování („duck typing“): vyhovuje každá třída, která má atribut
nazev, bez dědění. - Iterable / Sequence v parametrech jsou lepší než
list– funkce pak přijme i n-tici nebo generátor. - Any vypíná kontrolu. Používejte střídmě.
Generika
Python 3.12 přinesl novou syntaxi typových parametrů:
def prvni[T](polozky: Sequence[T]) -> T:
return polozky[0]
type Matice = list[list[float]]
Pro starší verze použijte TypeVar:
from typing import TypeVar
T = TypeVar("T")
def prvni(polozky: Sequence[T]) -> T:
return polozky[0]
Instalace a spuštění mypy
pip install mypy
mypy src/
Mypy ve výchozím stavu nekontroluje těla funkcí bez anotací. To je záměr: umožňuje postupné zavádění. Když tedy spustíte mypy na starý kód a nic nenajde, neznamená to, že je bez chyb.
Konfigurace v pyproject.toml
Rozumný start pro existující projekt:
[tool.mypy]
python_version = "3.12"
warn_unused_ignores = true
warn_redundant_casts = true
warn_return_any = true
check_untyped_defs = true
ignore_missing_imports = false
[[tool.mypy.overrides]]
module = ["nejaka_stara_knihovna.*"]
ignore_missing_imports = true
Pro nový projekt rovnou zapněte přísný režim:
[tool.mypy]
strict = true
strict mimo jiné vyžaduje anotace u všech funkcí a zakazuje implicitní Any.
Knihovny bez typů
Pokud knihovna nemá typy, mypy hlásí missing library stubs. Řešení:
- Zkuste nainstalovat stuby:
pip install types-requests,types-PyYAMLapod. Mypy je umí navrhnout:mypy --install-types. - Pokud stuby neexistují, přidejte modul do
overridessignore_missing_imports = true.
Postupné zavádění v praxi
- Přidejte mypy s mírnou konfigurací a opravte nalezené chyby.
- Anotujte nejdřív veřejná rozhraní – funkce, které volají jiné moduly.
- Zapínejte přísnější volby modul po modulu přes
[[tool.mypy.overrides]], napříkladdisallow_untyped_defs = truepro už otypované balíčky. - Přidejte mypy do CI, aby se nové chyby nedostaly do hlavní větve.
Ignorování konkrétních chyb
vysledek = podivna_funkce() # type: ignore[no-untyped-call]
Vždy uvádějte kód chyby v hranatých závorkách. Holé # type: ignore umlčí všechno včetně budoucích chyb na stejném řádku. S volbou warn_unused_ignores vás mypy upozorní, když už ignore není potřeba.
Kontrola typu za běhu
Mypy je statický nástroj. Pro validaci dat zvenku (JSON, formuláře, konfigurace) potřebujete kontrolu za běhu – na to slouží Pydantic, který anotace využívá k validaci.
Alternativy
- pyright – kontrolor od Microsoftu, rychlý, pohání Pylance ve VS Code.
- Novější nástroje jako ty od Astralu nebo Pyrefly od Mety (oba zatím ve vývoji – ověřte si aktuální stav).
Pro začátek je mypy bezpečná volba s nejširší dokumentací. Když narazíte na nesrozumitelnou chybu typu „incompatible type“, vložte ji i s kódem do ColdHost AI v režimu Výuka – vysvětlení, proč mypy typ odvodil právě takhle, bývá rychlejší než hledání v issues.