如何解决来自 pyright 的 "type is partially unknown" 警告?

How to solve "type is partially unknown" warning from pyright?

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

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

Declared return type, "DataLoader[Unknown]", is partially unknown Pyright (reportUnknownVariableType)

查看 pytorch 的类型存根 DataLoader(减少到重要部分):

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

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

据我所知,DataLoader 的通用类型 T_co 应该由 __init__ 数据集参数定义。

Pyright 还抱怨我的 Dataset 类型定义:

Type of parameter "dataset" is partially unknown Parameter type is "Dataset[Unknown]" Pyright (reportUnknownParameterType)

查看 Dataset 类型存根:

class Dataset(Generic[T_co]):
    def __getitem__(self, index: int) -> T_co: ...

向我表明类型应该由 __getitem__ 的 return 类型推断。

我的数据集 __getitem__ 的类型签名如下所示:

def __getitem__(self, index: int) -> Tuple[Tensor, Tensor]:

基于此,我希望 DatasetDataLoader 可以推断为 Dataset[Tuple[Tensor, Tensor]]DataLoader[Tuple[Tensor, Tensor]],但事实并非如此。

我的猜测是 pyright 无法在此处静态推断类型。

我想我可以这样定义我自己的类型签名:

Dataset[Tuple[Tensor, Tensor]]

但这实际上导致我的 python 脚本崩溃:

TypeError: 'type' object is not subscriptable

如何正确定义 DatasetDataLoader 的类型?

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

Eric Traut 详细解释了问题所在以及 pyright 正在按设计运行。 我试着在这里给出要点的要点。

问题解释

如果未提供 return 类型,Pyright 会尝试推断它们,但如果像本例那样提供,则需要完全键入。 Pyright 不会填写给定类型注释的缺失部分。

例如,pyright 将尝试为以下函数定义推断 return 类型:

def get_dataset():

但是如果 return 类型被指定为 Dataset 那么这就是 pyright 期望的 return 类型。

def get_dataset() -> Dataset:

在这种情况下,Dataset 是一个通用的 class,它不像 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 不警告 "unsubscriptable-object".

另一种解决方法是像这样引用类型定义:

def get_dataset() -> "Dataset[int]":