Аннотации типов в Python
В больших проектах бывает трудно с первого взгляда понять, какие данные принимает функция. Сравните два варианта одной и той же заготовки:
Python 3.13# Что такое user? Объект? Строка с именем? Что вернёт функция? def get_discount(user): pass # Сразу понятно: передаём ID (число), получаем скидку (число с точкой) def get_discount(user_id: int) -> float: pass
Приписки : int и -> float — это аннотации типов: подсказки о том, значения каких типов функция принимает и возвращает.
Подсказки, а не запреты
Python остаётся языком с динамической типизацией: во время работы программы аннотация ничего не проверяет. Убедимся:
Python 3.13def double(x: int) -> int: return x * 2 print(double(5))10print(double("ха")) # аннотация не остановила строкухаха
Программа не упала: для Python аннотация — просто пометка. Пользу из неё извлекают инструменты вокруг кода — редактор и IDE. Чем именно она полезна, разберём в конце урока.
Базовый синтаксис
Для переменной тип пишут через двоеточие после имени:
Python 3.13name: str = "Алексей" age: int = 28 height: float = 1.82 is_developer: bool = True
В функциях аннотируют аргументы и — через стрелку -> — возвращаемое значение:
Python 3.13def greet(name: str, age: int) -> str: return f"Привет, {name}! Тебе {age} лет." message = greet("Иван", 25) print(message)Привет, Иван! Тебе 25 лет.
Если функция ничего не возвращает, пишут -> None.
Типизация коллекций
Для коллекций указывают и тип содержимого:
Python 3.13numbers: list[int] = [1, 2, 3, 4, 5] # Ключи — строки, значения — числа user_ages: dict[str, int] = { "Иван": 25, "Анна": 22 } # Кортеж с чёткой структурой: (строка, целое, число с точкой) user_info: tuple[str, int, float] = ("Алексей", 30, 75.5)
Значение или None
Частый случай: функция возвращает значение — или None, если ничего не нашлось. Это записывают через вертикальную черту:
Python 3.13def get_user_email(user_id: int) -> str | None: if user_id == 1: return "admin@example.com" return None
Та же черта объединяет любые типы: int | float — «целое или с точкой»:
Python 3.13def process_price(price: int | float) -> float: return float(price) * 1.2
Псевдонимы типов
Чтобы не повторять длинные типы по много раз, им дают имена:
Python 3.13Coordinates = tuple[float, float] UserDict = dict[str, str | int] def get_location() -> Coordinates: return (55.7558, 37.6173) def process_user(user: UserDict) -> None: pass
Зачем всё это нужно
- Меньше ошибок: редактор подчеркнёт несоответствие ещё до запуска, если передать строку туда, где ожидается int.
- Точное автодополнение: IDE знает тип значения — значит, знает и его методы.
- Код проще читать: по заголовку def get_user(user_id: int) -> dict[str, str]: всё ясно без чтения тела функции.
Проверка понимания
Как описать функцию, которая принимает целое число и строку-или-None, а возвращает список чисел?
