Подсказки типа Python - лучший синтаксис для cast ()?

Недавно я начал использовать подсказки типов в своем коде и до сих пор обнаружил, что они быть (в основном) очень полезным.

Однако одна вещь, которая мне действительно не нравится, — это синтаксис, заставляющий средство проверки типов предполагать, что переменная имеет определенный тип. Учитывая этот пример:

import itertools
from typing import Iterable, Tuple
x: Iterable[Tuple[str, str]] = itertools.combinations('abc', 2)
# error: Incompatible types in assignment (expression has type "Iterable[Tuple[str, ...]]", variable has type "List[Tuple[str, str]]")

Насколько я могу судить, рекомендуемый способ обойти это — явно cast объект, чтобы заставить средство проверки типов использовать указанный тип, например:

import itertools
from typing import Iterable, Tuple, cast
x = cast(Iterable[Tuple[str, str]], itertools.combinations('abc', 2))

Я лично нахожу это решение немного грубым. Меня в первую очередь беспокоит то, что неопытному читателю не ясно, что cast существует исключительно для помощи статическому анализатору. (Если бы я еще не знал, я бы предположил, основываясь на имени и контексте, что он преобразует и делает копию в объект указанного типа, когда на самом деле нет затрат времени выполнения.)

cast выглядит как любой старый вызов функции. Когда я вижу, что функция вызывается для значения, я ожидаю, что значение будет видоизменено и/или возникнут какие-то другие побочные эффекты, но в этом случае единственным побочным эффектом является то, что mypy перестает жаловаться. Подсказки типов сами по себе имеют особый синтаксис, но я чувствую, что это размывает границы смесью нового синтаксиса ввода и традиционного синтаксиса Python. (Это уже немного размыто, так как вы должны import типы и можете их компоновать, но это другой разговор.)

Есть ли альтернативный синтаксис для поведения, подобного cast? Я ничего не нашел, но я надеялся на что-то вроде:

x1 = itertools.combinations('abc', 2)) # cast: Iterable[Tuple[str, str]] 

x2: Iterable[Tuple[str, str]] = itertools.combinations('abc', 2)) # type: cast

x3: Cast[Iterable[Tuple[str, str]]] = itertools.combinations('abc', 2))

person 0x5453    schedule 01.04.2019    source источник
comment
Я не верю, что есть какая-то альтернатива, нет. Вероятно, это было компромиссное решение. Вам, вероятно, следует пометить это mypy   -  person juanpa.arrivillaga    schedule 01.04.2019
comment
Предполагать, что функция будет иметь побочные эффекты, было бы хорошей привычкой, поскольку она проистекает из многолетней практики злоупотребления термином функция в сообществе языков программирования. Однако само имя cast предполагает, что оно ничего не делает, кроме как возвращает одно и то же значение. Я также сомневаюсь, что неопытный пользователь споткнется о это в отношении подсказки типа.   -  person chepner    schedule 01.04.2019
comment
@chepner: я не уверен, о чем ты? typeshed должен объявлять все, что связано с product, permutations и combinations, как Iterators; это ошибка, что combinations и combinations_with_replacement объявлены как Iterables (product/permutations правильно объявлены как Iterators).   -  person ShadowRanger    schedule 01.04.2019
comment
@ShadowRanger Приведение необходимо, чтобы установить размер внутреннего кортежа (Tuple[str, str] вместо Tuple[str, ...]). Обычно переменный размер имеет смысл, поскольку combinations может зависеть от значения времени выполнения, но в моем случае мне всегда нужны только последовательности длины 2.   -  person 0x5453    schedule 01.04.2019
comment
Я не знаю, действительно ли это менее уродливо, но вы могли бы сделать x: Iterable[Tuple[str, str]] = ((a, b) for (a, b) in itertools.combinations('abc', 2)).   -  person Nathan Vērzemnieks    schedule 22.04.2019


Ответы (1)


На самом деле последняя версия Mypy возвращает правильный тип Iterator[Tuple[str, str]].

Это изменение было введено в Typeshed в PR https://github.com/python/typeshed/pull/. 4309.

Если вы не можете обновить mypy до последней версии, вы можете проверить последнюю версию с typeshed и использовать параметр конфигурации custom_typeshed_dir.

См. https://mypy.readthedocs.io/en/stable/config_file.html#confval-custom_typeshed_dir для получения дополнительной информации.

person Sebastian Kreft    schedule 15.12.2020