Как решить предупреждение "тип частично неизвестен" от pyright?
Я использую строгую проверку типов через pyright.
Когда у меня есть метод, возвращающий pytorch DataLoader
, то Пайрайт жалуется на определение моего типа:
Объявленный возвращаемый тип "DataLoader[Unknown]" частично неизвестен Pyright (reportUnknownVariableType)
Взглянув на заглушку типа от pytorch's DataLoader
(сведено к важным частям):
class DataLoader(Generic[T_co]):
dataset: Dataset[T_co]
@overload
def __init__(self, dataset: Dataset[T_co], ...
Насколько я понимаю, общий тип T_co
из DataLoader
должен быть определен __init__
параметр набора данных.
Пайрайт также жалуется на мои Dataset
определение типа:
Тип параметра "набор данных" частично неизвестен. Тип параметра - "Набор данных [Неизвестно]" Pyright (reportUnknownParameterType)
Взглянув на Dataset
введите заглушку:
class Dataset(Generic[T_co]):
def __getitem__(self, index: int) -> T_co: ...
показывает мне, что тип должен определяться возвращаемым типом __getitem__
.
Подпись типа моего набора данных __getitem__
выглядит так:
def __getitem__(self, index: int) -> Tuple[Tensor, Tensor]:
Исходя из этого, я ожидал Dataset
а также DataLoader
выводиться как Dataset[Tuple[Tensor, Tensor]]
а также DataLoader[Tuple[Tensor, Tensor]]
Но это не тот случай.
Я предполагаю, что pyright не может статически вывести типы здесь.
Я думал, что могу определить сигнатуру типа вот так:
Dataset[Tuple[Tensor, Tensor]]
но на самом деле это приводит к сбою моего скрипта python:
TypeError: объект типа не может быть подписан
Как правильно определить тип для Dataset
а также DataLoader
?
2 ответа
Поскольку на этот вопрос не было ответа, я не был уверен, действительно ли это ошибка в pyright. Поэтому я открыл эту проблему в репозитории github: https://github.com/microsoft/pyright/issues/698
Эрик Траут подробно объяснил, в чем проблема, и что pyright работает так, как задумано. Здесь я постараюсь изложить суть основных моментов.
Объяснение проблемы
Pyright пытается определить возвращаемые типы, если они не предоставлены, но если они предоставлены, как в этом случае, они должны быть полностью типизированы.Pyright не заполняет недостающие части аннотации данного типа.
Например, pyright попытается вывести тип возвращаемого значения для следующего определения функции:
def get_dataset():
Но если тип возврата задан как Dataset
тогда это тип возвращаемого значения, которого ожидает pyright.
def get_dataset() -> Dataset:
В этом случае Dataset
- это общий класс, который не обрабатывает индексы вроде Dataset[int]
. В Python 3.7 (который мы используем) интерпретатор Python будет оценивать эти аннотации типов, что приводит к упомянутому исключению.
Решение
Начиная с Python 3.10 интерпретатор Python больше не будет оценивать аннотации типов, и следующая аннотация типов будет работать только:
def get_dataset() -> Dataset[int]:
Начиная с Python 3.7, это поведение можно включить с помощью следующего импорта:
from __future__ import annotations
Это задокументировано в PEP 563. Вам также необходимо отключить правило E1136, чтобы pylint не предупреждал о "неподписываемом-объекте".
Другой обходной путь - процитировать определение типа следующим образом:
def get_dataset() -> "Dataset[int]":
"python.analysis.diagnosticSeverityOverrides": {
"reportUnknownVariableType": "none",
"reportUnknownArgumentType": "none",
"reportUnknownLambdaType": "none",
"reportUnknownMemberType": "none",
"reportUnknownParameterType": "none",
"reportMissingParameterType": "none"
}