Поддерживает ли оператор with подсказку типа?

16

Можете ли вы определить подсказку типа для переменной, определенной с помощью withсинтаксиса?

with example() as x:
    print(x)

Я хотел бы напечатать подсказку выше, чтобы сказать, что xэто str(в качестве примера).

Единственный обходной путь, который я нашел, - это использование промежуточной переменной, но это кажется хакерским.

with example() as x:
    y: str = x
    print(y)

Я не могу найти пример в печатной документации .

Reactgular
источник
6
Не должны ли контролеры типов выводить тип в xкачестве возвращаемого типа example().__enter__()?
pschill
2
Почему вы хотите аннотировать, xкогда это просто возвращаемый тип example.__enter__? В идеале вы аннотировали этот метод / функцию.
a_guest
1
xне возвращаемое значение example; это возвращаемое значение example().__enter__().
Чепнер
Большинство методов, которые я нашел, не определяют подсказку типа для возвращаемого значения.
Reactgular
1
@Reactgular Тогда решение состоит в том, чтобы создать заглушку для этой функции, чтобы средство проверки типов могло вывести тип. Обычно вы аннотируете границы API, а не внутри. В этом случае ясно, что тип исходит от example. Аннотирование example.__enter__означает одну аннотацию, в то время как при вашем подходе вам придется аннотировать во всех местах, где используется этот диспетчер контекста, а также вообще, как пользователь должен знать, какой тип возвращаемого API в любом случае есть, если он не предоставляется?
a_guest

Ответы:

11

PEP 526, который был реализован в Python 3.6, позволяет аннотировать переменные. Вы можете использовать, например,

x: str
with example() as x:
    [...]

или

with example() as x:
    x: str
    [...]
Pschill
источник
Это также работает для других блоков кода, таких как for. Отличный ответ, спасибо.
Reactgular
Если менеджер контекста не намекает на то, что __enter__вернет метод, набор текста xне имеет смысла. mypyс радостью позволят привязать значение любого типа x.
Чепнер
@chepner Да, ты прав. PyCharm распознает xкак strв обоих случаях, но mypyне делает.
pschill
14

Обычно аннотации типов размещаются на границах API. В этом случае тип должен быть выведен из example.__enter__. Если эта функция не объявляет какие-либо типы, решение состоит в том, чтобы создать соответствующий файл-заглушку , чтобы средство проверки типов могло вывести этот тип.

В частности, это означает создание .pyiфайла с тем же основанием, что и модуль, из которого Exampleбыл импортирован. Затем можно добавить следующий код:

class Example:
    def __enter__(self) -> str: ...
    def __exit__(self, exc_type, exc_value, exc_traceback) -> None: ...
Гость
источник