6

我正在通过 pyright 使用严格的类型检查。

当我有一个返回 pytorch 的方法时DataLoader,pyright 会抱怨我的类型定义:

声明的返回类型“DataLoader[Unknown]”部分未知 Pyright (reportUnknownVariableType)

看一下 pytorch 的类型存根DataLoader(简化为重要部分):

class DataLoader(Generic[T_co]):
    dataset: Dataset[T_co]

    @overload
    def __init__(self, dataset: Dataset[T_co], ...

据我所知,泛型类型T_co应该DataLoader__init__数据集参数定义。

Pyright 还抱怨我的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:“类型”对象不可下标

如何正确定义Datasetand的类型DataLoader

4

1 回答 1

9

由于没有对此问题的答复,我不确定它是否实际上是 pyright 中的错误。因此,我在 github 存储库上打开了这个问题:https ://github.com/microsoft/pyright/issues/698

Eric Traut 详细解释了问题所在以及 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]":
于 2020-05-30T16:52:53.477 回答