Рассмотрим следующую функцию псевдоидентичности:
Код: Выделить всё
def g(x, y): return x, y
Я ищу способ чтобы аннотировать эту функцию, чтобы mypy мог точно определить тип возвращаемого значения. Например, я ожидаю, что g(1,2) приведет к кортежу целых чисел, g('hi', 'world') к кортежу str, g (1, 'world') в tuple[int, str], а недопустимые регистры приведут к ошибке.
Я наивно написал:< /p>
Код: Выделить всё
from typing import TypeVar
T = TypeVar('T', bound=int)
def g(x: T | str, y: T | str) -> tuple[T | str, T | str]:
return x, y
Однако, когда я выполняю mypy в этом фрагменте следующим образом:
Код: Выделить всё
reveal_type(g(3, 4))
reveal_type(g('hello', 'world'))
reveal_type(g('hello', 2))
Код: Выделить всё
main.py:8: note: Revealed type is "tuple[Union[builtins.int, builtins.str], Union[builtins.int, builtins.str]]"
main.py:9: note: Revealed type is "tuple[builtins.str, builtins.str]"
main.py:10: note: Revealed type is "tuple[Union[builtins.int, builtins.str], Union[builtins.int, builtins.str]]"
Success: no issues found in 1 source file
Вторая строка — это то, что я ожидал (кортеж строк), но два других вызова должны (или могут) быть уточнены до tuple[int, int] и кортеж[str, int]. Результат аналогичен PyRight и просто аналогичен Pyre (последний указывает tuple[str, Literal[2]] вместо tuple[str, int] в последнем случае по какой-то неизвестной причине ).
Это что-то выходит за рамки модуля ввода или за пределами mypy? Я что-то упустил?
Обратите внимание, что я не могу написать T = TypeVar('T', int, str). Хотя это работает (для приведенного выше примера), помните, что я использовал int для упрощения случая, когда на практике я хочу, чтобы T был любым классом, реализующим мой протокол Comparable (поэтому мне нужно чтобы определить T с верхней границей, а не со списком точных типов, это T = TypeVar('T',bound=Comparable)).
< hr />
Чтобы добавить дополнительный контекст для этого вопроса (не читайте, если вам все равно , библиотека, которую я хочу аннотировать, определяет класс Interval, состоящий из двух границ (нижний и верхний). Этими границами может быть любой объект, поддерживающий сравнение (например, целые числа, числа с плавающей запятой, даты). Для обработки бесконечных и полубесконечных интервалов библиотека определяет два специальных объекта, а именно inf и -inf, которые являются соответственно одноэлементными экземплярами _PInf и _NInf. Моя цель — аннотировать этот класс Interval, чтобы mypy мог проверить, является ли Interval(x, y) допустимым (т. е. x и y имеют один и тот же Comparable< Тип /code> или x или y или оба являются экземплярами _PInf _NInf).
Обобщая приведенный выше пример, Сейчас у меня есть что-то вроде этого:
Код: Выделить всё
Comparable = ... # Protocol with __eq__, __lt__, __le__, ...
T = TypeVar('T', bound=Comparable)
Bound: TypeAlias = T | _PInf | _NInf
class Interval(Generic[T]):
def __init__(self, lower: Bound[T], upper: Bound[T]) -> None:
...
Подробнее здесь: https://stackoverflow.com/questions/780 ... an-union-i