Type Hints в Python и проверка типов с инструментом mypy

В этом уроке вы узнаете о подсказках типов данных (Type Hints) в Python и о том, как использовать инструмент mypy для статической проверки типов.

Содержание

Что такое подсказки типов в Python?

Некоторые языки программирования, например C/C++, имеют статическую типизацию. Это означает, что вам необходимо заранее объявить типы переменных, параметров и возвращаемых значений функции. Предопределенные типы позволяют компиляторам проверять код перед компиляцией и запуском программы.

Python использует динамическую типизацию, при которой переменные, параметры и возвращаемые значения функции могут быть любого типа. Кроме того, типы переменных могут меняться во время работы программы.

Как правило, динамическая типизация упрощает программирование и вызывает непредвиденные ошибки, которые можно обнаружить только до тех пор, пока программа не запустится.

Type Hints в Python предоставляют вам дополнительную статическую типизацию, позволяющую использовать преимущества как статической, так и динамической типизации.

В следующем примере определяется простая функция, которая принимает строку и возвращает другую строку:

def say_hi(name):
    return f'Hi {name}'


greeting = say_hi('John')
print(greeting)

Вот синтаксис добавления подсказок типа данных к параметру и возвращаемому значению функции:

parameter: type
-> type

Например, ниже показано, как использовать подсказки типа для параметра name и возвращаемого значения функции Say_hi():

def say_hi(name: str) -> str:
    return f'Hi {name}'


greeting = say_hi('John')
print(greeting)

Выход:

Hi John

В этом новом синтаксисе параметр name имеет тип str:

name: str

И возвращаемое значение функции say_hi() также имеет тип str:

-> str

Помимо типа str, для подсказок типов можно использовать другие встроенные типы, такие как int, float, bool и bytes.

Важно отметить, что интерпретатор Python полностью игнорирует подсказки типов. Если вы передадите число функции say_hi(), программа запустится без каких-либо предупреждений или ошибок:

def say_hi(name: str) -> str:
    return f'Hi {name}'


greeting = say_hi(123)
print(greeting)

Выход:

Hi 123

Чтобы проверить синтаксис подсказок типов, вам необходимо использовать инструмент проверки статического типа.

Инструмент статической проверки типа: mypy

В Python нет официального инструмента статической проверки  типов. На данный момент самым популярным сторонним инструментом является Mypy. Поскольку Mypy — сторонний пакет, вам необходимо установить его с помощью следующей команды pip:

pip instal mypy

После установки mypy вы можете использовать его для проверки типа перед запуском программы, используя следующую команду:

mypy app.py

Появится следующее сообщение:

app.py:5: error: Argument 1 to "say_hi" has incompatible type "int"; expected "str"
Found 1 error in 1 file(checked 1 source file)

Ошибка указывает на то, что аргумент say_hi имеет значение int, а ожидаемый тип — str.

Если вы снова измените аргумент на строку и снова запустите mypy, появится сообщение об успехе:

Success: no issues found in 1 source file

Подсказки типов и вывод типов

При определении переменной вы можете добавить подсказку типа следующим образом:

name: str = 'John'

Тип переменной имени — str. Если вы присвоите переменной имени значение, не являющееся строкой, средство проверки статического типа выдаст ошибку. Например:

name: str = 'Hello'
name = 100

Ошибка:

app.py:2: error: Incompatible types in assignment(expression has type "int", variable has type "str")
Found 1 error in 1 file(checked 1 source file)

Добавление типа к переменной не является необходимым, поскольку средства проверки статического типа обычно могут определить тип на основе значения, присвоенного переменной.

В этом примере значением name является литеральная строка, поэтому средство проверки статического типа определит тип переменной name как str. Например:

name = 'Hello'
name = 100

Выдаст ту же ошибку:

app.py:2: error: Incompatible types in assignment(expression has type "int", variable has type "str")
Found 1 error in 1 file(checked 1 source file)

Добавление подсказок для нескольких типов

Следующая функция add() возвращает сумму двух чисел:

def add(x, y):
    return x + y

Числа могут быть целыми числами или числами с плавающей запятой. Вы можете использовать модуль для установки type hints для нескольких типов.

Сначала импортируйте Union из модуля typing:

from typing import Union

Во-вторых, используйте Union для создания типа объединения Union, включающего int и float:

def add(x: Union[int, float], y: Union[int, float]) -> Union[int, float]:
    return x + y

Вот полный исходный код:

from typing import Union


def add(x: Union[int, float], y: Union[int, float]) -> Union[int, float]:
    return x + y

Начиная с Python 3.10, вы можете использовать X | Синтаксис Y для создания типа Union, например:

def add(x: int | float, y: int | float) -> int | float:
    return x + y

Присвоение псевдонимов

Python позволяет вам назначать псевдоним типу и использовать его для подсказок типов. Например:

from typing import Union

number = Union[int, float]


def add(x: number, y: number) -> number:
    return x + y

В этом примере мы присваиваем типу Union[int, float] псевдоним Number и используем псевдоним Number в функции add().

Добавление подсказок типов для списков, словарей и множеств

Вы можете использовать следующие встроенные типы, чтобы установить подсказки типов для списка, словаря и множества:

  • list
  • dict
  • set

Если вы введете подсказки в переменную в виде списка, а затем присвоите ей словарь, вы получите ошибку:

ratings: list = [1, 2, 3]
ratings = {1: 'Bad', 2: 'average', 3: 'Good'}

Ошибка:

app.py:3: error: Incompatible types in assignment(expression has type "Dict[int, str]", variable has type "List[Any]")
Found 1 error in 1 file(checked 1 source file)

Чтобы указать типы значений в списке, словаре и наборах, вы можете использовать псевдонимы типов из модуля typing:

Псевдоним типа Встроенный тип
List list
Tuple tuple
Dict dict
Set set
Frozenset frozenset
Sequence Для списка, кортежа и любого другого типа данных последовательности.
Mapping Для dict, set, Frozeset и любого другого типа данных сопоставления.
ByteString Для типов bytes, bytearray и MemoryView.

Например, следующее определяет список целых чисел:

from typing import List

ratings: List[int] = [1, 2, 3]

Тип None

Если функция не возвращает значение явно, вы можете использовать None для ввода подсказки возвращаемого значения. Например:

def log(message: str) -> None:
    print(message)
Похожие посты
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *