def add(a: int, b: int) → int:

msg: str = f"Сумма чисел {a} и {b} = {a + b}"
print(msg)
return a + b


В данном примере мы видим функцию которая принимает два целых числа, и возвращает число. В самой функции мы создаем переменную msg и указываем что это строка.

Для аннотации типа значений аргумента используется двоеточие и после идёт указываемый тип. Для указания возвращаемого значения используется ->и после возвращаемый тип.


❗️ Заметим что Python не проверяет типы при вызове функции. Аннотации просто подсказывают тип.


Если мы вызовем add("Hello ", "World") то получим вывод "Сумма чисел Hello и World = Hello World".
Но зачем они нужны если они не влияют на код?

  1. Это помогает другим разработчикам понимать ваш код.
    Пример ситуации:
    Вы создали функцию get_user которая принимает id пользователя и возвращает его объект:
    users = {123: "User"}
    def get_user(user_id):
    return users.get(user_id)

    Если другой разработчик попытается передать ключ "123", функция вернет None, так как в словаря наш пользователь записан ключом 123 типа int. Если мы укажем в аннотации все данные:
    users: dict[int, str] = {123: "User"}
    def get_user(user_id: int) -> str | None:
    return users.get(user_id)

  2. Само-документирует код.
    Аннотации позволят вам не указывать в документации их тип.

  3. IDE и статические анализаторы используют аннотации для проверки типов и подсказок.
    Давайте рассмотрим как использовать статический анализатор mypy

  4. Устанавливаем mypy: pip install mypy.

  5. Запускаем проверку mypy main.py или другой ваш файл или директория.

  6. Для строгой проверки используйте флаг —strict mypy —strict main.py
    Вам выведется подробное сообщение анализа.

❓Какие есть типы аннотаций?

  1. Базовые типы.
    int, str, float, bool и т.п - это всё простые типы. Они явно указывают что объект является их типом.

  2. Коллекции.
    Давайте рассмотрим основные:

  • list - Для указания типа используются квадратные скобки. Список чисел: list[str]

  • tuple - Для указания точного кортежа например кортежа из трёх строк используйте такую аннотацию: tuple[str, str, str], для переменного количества аргументов используйте Ellipsis(Троеточие): tuple[str, ...]

  • dict - Указывается два значения, первый это тип ключа, второй это тип значения. Пример словарь строка-число dict[str, int]

  • set, frozenset - Аналогично list и tuple. Тип значение указывается в квадратных скобках set[str]

  1. Другие аннотации. Для других аннотаций используется модуль typing из стандартной библиотеки

  • Union. Если вы хотите указать что тип может быть как одним так и другим типом используйте синтаксис int | str(Число или строка). Для старых версий Python используйте Union[int, str].

  • Literal. Если вы хотите указать что переменная/аргумент/функция принимает только конкретные типы из определённого списка, используйте Literal['+', '-', "*", "/"].

  • Optional - Если вы хотите указать что тип может быть как одним так и другим типом используйте синтаксис int | None (Число или None). ❗️ В Python 3.9 и ниже используйте Optional[int]

  • Any. Если вы хотите указать что переменная/аргумент/функция принимает произвольное значение, то используйте Any. ❗️ Any - спорный тип. При его использовании теряется смысл типизации. Используйте в местах где вы точно уверенны что тип произвольный. 🔥 Если вы используете аннотации из typing, не забудьте импортировать явно from typing import Optional, Union, Literal, Any или использовать точечную нотацию typing.Any

✍️ Это был первый обзор аннотаций в Python. В этом посте я покрыл не все темы аннотаций. В последующих постах я разберу как создавать свои Generic классы. Что такое Protocol и чем он отличается от абстрактных классов. Более продвинутые аннотации и как их использовать.

❗️ Если вы ещё не используете аннотации, то используйте их в своем коде!

PEP 484 — PEP про аннотации
typing — Документация typing
Binobinos — Python (https://t.me/binobinosdev) #typehints