# Добавлено в Python 3.13. from typing import TypeIs class Parent: pass class Child(Parent): pass def is_parent(val: object) -> TypeIs[Parent]: return isinstance(val, Parent) def run(arg: Child | Unrelated): # Тип `arg` сужается до пересечения # из `Parent` и `Child`, что эквивалентно `Child` if is_parent(arg): ...
typing.TypeIs[]
:Добавлено в Python 3.13.
Специальная конструкция типизации TypeIs[]
модуля typing
предназначена для маркировки функций предиката определяемого пользователем типа.
typing.TypeIs[]
можно использовать для аннотирования типа возвращаемого значения функции-предиката определяемого пользователем типа. Конструкция typing.TypeIs
принимает только один аргумент типа. Во время выполнения функции, помеченные таким образом, должны возвращать логическое значение и принимать хотя бы один позиционный аргумент.
Цель TypeIs[]
- сужение типов - метод, используемый средствами проверки статических типов для определения более точного типа выражения в потоке кода программы. Обычно сужение типа выполняется путем анализа потока условного кода и применения сужения к блоку кода. Условное выражение здесь иногда называют "предикатом типа":
def is_str(val: str | float): # Предикат типа 'isinstance' if isinstance(val, str): # Тип `val` сужается до `str` ... else: # В противном случае тип `val` сужается до `float`. ...
Иногда было бы удобно использовать определяемую пользователем логическую функцию в качестве предиката типа. Такая функция должна использовать TypeIs[...]
или TypeGuard
в качестве возвращаемого типа, чтобы предупредить об этом средства проверки статических типов. TypeIs
обычно имеет более интуитивное поведение, чем typing.TypeGuard
, но его нельзя использовать, когда типы ввода и вывода несовместимы (например, list[object]
со list[int]
) или когда функция не возвращает True
для всех экземпляров суженного типа.
Использование -> TypeIs[NarrowedType]
сообщает средству проверки статического типа, что для данной функции:
True
, то тип его аргумента является пересечением исходного типа аргумента и NarrowedType
.False
, то тип его аргумента сужается, чтобы исключить NarrowedType
.from typing import assert_type, final, TypeIs class Parent: pass class Child(Parent): pass @final class Unrelated: pass def is_parent(val: object) -> TypeIs[Parent]: return isinstance(val, Parent) def run(arg: Child | Unrelated): if is_parent(arg): # Тип `arg` сужается до пересечения # из `Parent` и `Child`, что эквивалентно `Child` assert_type(arg, Child) else: # Тип `rg`` сужен, для исключения `Parent`, # так что остается только `Unrelated`. assert_type(arg, Unrelated)
Тип внутри typing.TypeIs
должен соответствовать типу аргумента функции. Если это не так, то средства проверки статического типа выдадут ошибку. Неправильно написанная функция typing.TypeIs
может привести к некорректному поведению системы типов. Ответственность за написание таких функций типобезопасным образом лежит на пользователе.
Если конструкция typing.TypeIs
является методом класса или экземпляра, то тип в TypeIs
сопоставляется с типом второго аргумента (после cls
или self
).
Короче говоря, форма def foo(arg: TypeA) -> TypeIs[TypeB]: ...
означает, что если foo(arg)
возвращает True
, то arg
является экземпляром TypeB
, а если он возвращает False
, то это не экземпляр TypeB
.