Как стать автором
Обновить
884.57
OTUS
Цифровые навыки от ведущих экспертов

Подсказки по типам Python — Как сузить количество типов с помощью TypeGuard

Время на прочтение2 мин
Количество просмотров4.3K
Автор оригинала: Adam Johnson

Ранее я уже рассказывал о сужении типов с помощью isinstance(), assert и Literal. В сегодняшней заметке мы рассмотрим TypeGuard, новый специальный тип, который позволяет нам создавать кастомные функции сужения типов.

TypeGuard был определен в PEP 647 и доступен в Python 3.10+ или в более старых версиях из typing-extensions. Гвидо ван Россум добавил поддержку в Mypy в версии 0.900, которая была опубликована накануне.

Напомним, что сужение типов использует определенные выражения для вывода о том, что в данном блоке переменная имеет более ограниченный тип, чем ее определение. Например, с помощью isinstance():

from __future__ import annotations

name: str | None

if isinstance(name, str):
    # name must be 'str'
    ...
else:
    # name must be None
    ...

Средства проверки типов, включая Mypy, поддерживают ограниченное количество выражений, таких как if isinstance(...). Но количество потенциально сужающих тип выражений бесконечно, особенно для параметризованных типов, таких как контейнеры. TypeGuard позволяет нам написать любое выражение типа и сообщить нашему средству для проверки типов, что оно их сужает.

Сужающая тип функция — такая, которая принимает хотя бы один аргумент и возвращает bool. Вместо того чтобы обозначить возвращаемый тип как bool, мы используем TypeGuard[T], где True означает, что первый аргумент имеет тип T, а False — нет. Возьмем этот пример, адаптированный из PEP:

from __future__ import annotations

from typing_extensions import TypeGuard


def is_str_list(value: list[object]) -> TypeGuard[list[str]]:
    """Are all list items strings?"""
    return all(isinstance(x, str) for x in value)


x: list[object]

reveal_type(x)
if is_str_list(x):
    reveal_type(x)

is_str_list() возвращает True, если в заданном списке содержатся только строки. Мы сообщаем Mypy, что он может сузить тип value до list[str] с помощью возвращаемого типа TypeGuard.

Запустив Mypy на этом файле, мы видим следующий результат вызова reveal_type():

$ mypy --strict example.py
example.py:13: note: Revealed type is "builtins.list[builtins.object]"
example.py:15: note: Revealed type is "builtins.list[builtins.str]"

Второе примечание показывает, что Mypy знает, что x должен быть списком строк в блоке if. Это позволяет нам использовать элементы списка в качестве str без каких-либо ошибок. Отлично!

TypeGuard отличается гибкостью, поскольку позволяет нам писать произвольный код для сужения выражений. Правда, он заставляет нас переносить даже короткие выражения в отдельные функции, но это часто бывает полезно для читабельности кода.

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

PEP 647 также показывает общие функции TypeGuard с TypeVar, но когда я попробовал примеры, то обнаружил, что Mypy 0.901 пока не поддерживает их. Для TypeGuard существует несколько открытых проблем, так что, похоже, Mypy может воспользоваться нашим вкладом в их решение!

И пусть ваши типы будут хорошо защищены.


Приглашаем всех желающих на открытое занятие по теме «Знакомство с веб разработкой на Flask». На этом занятии мы с вами познакомимся с основами веб-разработки на Flask, а также научимся создавать и рендерить шаблоны страниц. Попробуем создать Flask приложение, затем создать роуты и в конце обработать различные HTTP методы на Flask. Регистрация по ссылке.

Теги:
Хабы:
Всего голосов 6: ↑5 и ↓1+4
Комментарии0

Публикации

Информация

Сайт
otus.ru
Дата регистрации
Дата основания
Численность
101–200 человек
Местоположение
Россия
Представитель
OTUS