Статьи

Учебные материалы по языку Python — от основ до продвинутых тем

Типизация и тестирование

Страница 16 из 34 · 2026-10-26 · 2 мин чтения

Аннотации типов

Python остаётся динамическим языком, но поддерживает необязательные подсказки типов. Интерпретатор их не проверяет — они нужны редакторам, статическим анализаторам и читателям кода.

def add(a: int, b: int) -> int:    return a + bname: str = "Anna"scores: list[int] = [5, 4, 5]user: dict[str, int] = {"age": 25}point: tuple[int, int] = (1, 2)

Необязательные значения и объединения

def find(items: list[str], key: str) -> str | None:    for item in items:        if item == key:            return item    return Nonedef parse(value: int | str) -> int:    return int(value)

Модуль typing

from typing import Callable, Iterable, Iterator, Any, TypeVar, ProtocolT = TypeVar("T")def first(items: Iterable[T]) -> T:    for item in items:        return item    raise ValueError("пустая последовательность")def apply(func: Callable[[int], int], value: int) -> int:    return func(value)class Drawable(Protocol):    def draw(self) -> None: ...

Протоколы описывают структурную типизацию: объект подходит, если у него есть нужные методы, наследование не требуется.

Статическая проверка

Для проверки используется отдельный инструмент, например mypy:

pip install mypymypy src/

Тестирование

unittest

Модуль входит в стандартную библиотеку:

import unittestdef divide(a, b):    if b == 0:        raise ZeroDivisionError("деление на ноль")    return a / bclass DivideTests(unittest.TestCase):    def test_normal(self):        self.assertEqual(divide(6, 3), 2)    def test_zero(self):        with self.assertRaises(ZeroDivisionError):            divide(1, 0)if __name__ == "__main__":    unittest.main()

Запуск всех тестов проекта:

python -m unittest discover

pytest

pytest — популярный сторонний фреймворк с более лаконичным синтаксисом:

pip install pytest
import pytestdef divide(a, b):    if b == 0:        raise ZeroDivisionError("деление на ноль")    return a / bdef test_normal():    assert divide(6, 3) == 2def test_zero():    with pytest.raises(ZeroDivisionError):        divide(1, 0)@pytest.mark.parametrize("a, b, expected", [(6, 3, 2), (10, 5, 2), (9, 3, 3)])def test_many(a, b, expected):    assert divide(a, b) == expected

Запуск:

pytest

Фикстуры

import pytest@pytest.fixturedef numbers():    return [1, 2, 3]def test_sum(numbers):    assert sum(numbers) == 6

Принципы хороших тестов

  • Один тест проверяет одно поведение
  • Тесты независимы друг от друга и не зависят от порядка запуска
  • Тесты быстрые и воспроизводимые
  • Название теста описывает проверяемый сценарий
  • Проверяйте не только штатные случаи, но и граничные значения и ошибки

Задания

  1. Добавьте аннотации типов к функциям из предыдущих уроков и прогоните mypy.
  2. Напишите набор тестов для функции проверки палиндрома, включая пустую строку и регистр букв.