Как мне определить тип, который инкапсулирует / описывает поведение / сигнатуру определенного модуля?

#python #mypy

#python #mypy

Вопрос:

Как мне определить тип, который инкапсулирует / описывает поведение / сигнатуру определенного модуля?

Проблема возникает из-за того, что мне приходится спать в моем коде, и я хочу абстрагироваться от этого. Я хочу внедрить макет для time библиотеки (вполне вероятно, что позже мне понадобятся другие функции time ), и я также хочу определить типы, чтобы включить статическую проверку типов (MyPy используется для проверки типов). Я также хотел бы, чтобы моя среда разработки имела надлежащее автозаполнение и документацию (что было бы в случае, если он может правильно угадать «тип»)

В настоящее время у меня есть следующий код, который работает и проходит мои проверки, однако это просто игнорирует ошибку MyPy (time не является допустимым типом):

 import time
[other relevant imports]
...

@dataclass
class RPUService:
    config: RPUConfig
    _time: time = time  # type: ignore[valid-type]
    ...

    def some_method(self):
         self._time.sleep(self.config.sleepytime)
  

Я также могу написать _time определение следующим образом:

 from types import ModuleType
_time: ModuleType = time
  

Или аналогично с Any :

 from typing import Any
_time: Any = time
  

Оба они действительны, но это лишает мою среду IDE возможности распознавать self._time как time библиотеку. (Или что-то похожее на time библиотеку)

Я мог бы определить a Protocol с сигнатурой time.sleep , но я бы предпочел не иметь накладных расходов на поддержание такого Protocol . (PEP-544)

Итак, мой вопрос: как мне определить тип, который инкапсулирует / описывает поведение определенного модуля?

(Если что-то неясно, пожалуйста, спросите)

Комментарии:

1. Способность вашей IDE автоматически заполнять ваш код не имеет ничего общего с mypy. Я думаю _time = time , это легко понять для IDE, но при объявлении _time определенного типа эта информация имеет более высокий приоритет, чем определение = time , поэтому она больше не автоматически заполняется как time , а как «объект объявленного типа».

2. Я бы выбрал протокольный подход. Похоже, это именно то, что вам нужно: «что-то, у чего есть метод ожидания, который принимает один аргумент с плавающей запятой». Вам даже не нужно определять все функции модуля time, а только те, которые вам нужны.

3. @Wombatz Хм, ну, на данный момент мне нужно только «что-то, что спит», поэтому протокол будет тривиальным для создания, однако он также скрывает всю остальную функциональность time . Поэтому, если в будущем коллега захочет использовать функциональность из time , ему / ей нужно будет знать, чтобы расширить протокол, что может быть не так просто, как хотелось бы. Если есть возможность сделать это без дополнительной абстракции, которую привносит протокол, я бы предпочел такой вариант.

4. @NiklasMertsch IDE, вероятно, выводит тип из присваивания, чтобы обеспечить автоматическое завершение, если тип не указан, и один из способов заставить это работать (иметь автозаполнение и никаких ошибок MyPy) — полностью удалить ввод текста. ( _time = time хотя это недопустимое объявление @dataclass , мне пришлось бы писать __init__ вручную). Это решение, однако я хотел бы узнать, как «решить» это с помощью статической типизации.

5. Есть ли необходимость в аннотации типа вообще? Если вы хотите автозаполнение, а ваша IDE выполняет автозаполнение без аннотаций, то по какой причине вы это делаете? Единственными «хорошими» аннотациями, которые я могу представить для этого случая, было бы что-то вроде _time: get_annotation(time) , но такой функциональности не существует. Кроме того, вам не нужно «что-то, что имеет сигнатуры time модуля», но вам нужен » time модуль», так зачем его явно аннотировать, если в любом случае это всегда один и тот же объект?