Урок 10 из 12 · 2 минуты чтения

Аннотации типов, mypy и Pydantic

Что дают аннотации и кто их проверяет, как аннотировать коллекции, Optional и объединения, обобщённые типы, mypy в проекте, проверка данных Pydantic.

Аннотации не проверяются при выполнении

def total(prices: list[float], discount: float = 0) -> float:
    return sum(prices) * (1 - discount)

total("abc")   # интерпретатор не возразит до ошибки внутри

Аннотации — подсказки для людей и инструментов. Их проверяют статические анализаторы — mypy и pyright, — а IDE берут из них автодополнение. Во время выполнения аннотации читают только те, кто делает это явно: Pydantic, FastAPI, dataclasses.

Как аннотировать

  • список, словарь, множество — list[int], dict[str, float], set[str];
  • кортеж фиксированной и любой длины — tuple[int, str], tuple[int, ...];
  • может быть None — int | None (раньше Optional[int]);
  • одно из — int | str;
  • функция — Callable[[int], str];
  • что угодно — object безопасно, Any отключает проверку.

Для параметров удобнее абстрактные типы из collections.abc: Iterable, Sequence, Mapping — так функция принимает и список, и кортеж, и генератор.

Optional означает «может быть None», а не «необязательный аргумент». Перед использованием значения типа X | None его проверяют на None — mypy на это и укажет.

Обобщённые типы

TypeVar связывает типы входа и выхода:

def first[T](items: list[T]) -> T:    # синтаксис Python 3.12
    return items[0]

first([1, 2])        # mypy знает: int
first(["a", "b"])    # str

До 3.12 то же пишут через T = TypeVar("T") и Generic[T] для классов. Ограничения — bound= или перечисление допустимых типов.

Protocol — утиная типизация для mypy

from typing import Protocol

class Closable(Protocol):
    def close(self) -> None: ...

def shutdown(items: list[Closable]) -> None:
    for item in items:
        item.close()

Подходит любой класс с методом close, без наследования. ABC, наоборот, требует явного наследования и проверяет реализацию при создании объекта.

mypy в проекте

mypy и pyright ставят как зависимость разработки, настраивают в pyproject.toml и запускают в CI:

[tool.mypy]
python_version = "3.12"
strict = true

Код без аннотаций mypy по умолчанию почти не проверяет, поэтому строгость наращивают постепенно — сначала новые модули. Для библиотек без типов ставят пакеты-заглушки (types-requests). Точечное отключение — # type: ignore[код] с понятной причиной.

Pydantic — проверка данных на входе

Pydantic проверяет и преобразует данные во время выполнения по аннотациям модели:

from pydantic import BaseModel, Field

class OrderIn(BaseModel):
    product_id: int
    count: int = Field(ge=1, le=100)
    comment: str | None = None

OrderIn.model_validate({"product_id": "42", "count": 2})   # "42" → 42
OrderIn.model_validate({"product_id": "abc", "count": 0})  # ValidationError

ValidationError указывает поле и причину. Обратно — model_dump() и model_dump_json(). Pydantic используют для запросов API, конфигурации, ответов внешних сервисов и LLM; FastAPI построен на нём.

Что запомнить

  • Аннотации проверяет mypy, а не интерпретатор.
  • X | None нужно проверить на None перед использованием.
  • Для параметров — Iterable и Sequence, для результата — конкретный тип.
  • mypy — в CI, строгость — постепенно.
  • Внешние данные — через Pydantic.

Проверка урока

Войдите, чтобы проверить себя: сданные проверки всех уроков курса отмечают его темы пройденными на карте и в ИПР.

Вопросы по теме

Читайте также

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования