1

以下代码按预期工作,但 os.path.join 在 VSCode 中使用 pyright 会产生类型错误,如图所示。

# python 3.6.9
# pyright 1.1.25
# windows 10
# vscode 1.42.1
import os
import tempfile

with tempfile.TemporaryDirectory() as tmpfolder:
    name = "hello.txt"
    path = os.path.join(tmpfolder, name)
    # No overloads for 'os.path.join(tmpfolder, name)' match parameters
    #   Argument types: (TypeVar['AnyStr', str, bytes], Literal['hello.txt'])

print(path)

我想我理解问题的直接原因,但认为它不应该发生。鉴于此,我有一些问题:

  1. 这是编写此代码的惯用方式吗?
  2. 是 tempfile、os、pyright 还是我的问题?
  3. 如果我无法升级 Python,抑制错误的最佳(即最不笨重)方法是什么?
4

1 回答 1

1

这似乎是对 pyright 的限制。

简而言之,tempfile.TemporaryDirectory该类的类型对于 AnyStr 而言是通用的。但是,您的示例代码省略了指定泛型类型,将其留给类型检查器来推断适当的内容。

在这种情况下,我认为类型检查器可以做几件合理的事情:

  1. 根据 typevar 选择一些默认的泛型类型,例如 'str' 或 'Union[str, bytes]'。例如,mypy 默认选择“str”,给“tmpfolder”一个类型的“str”。
  2. 选择一些占位符类型,例如“Any”、动态类型或 NoReturn(又名“底部”又名“无”)。这两种类型都是每种类型的有效子类型,因此保证是有效的占位符并且不会导致下游错误。这就是 pyre 和 pytype 所做的——他们推断“tmpfolder”分别具有“Any”和“nothing”类型。
  3. 尝试根据上下文推断正确的类型。一些类型检查器可能会尝试这样做,但我不知道有什么能完美地处理这种特殊情况。
  4. 报告错误并要求用户指定所需的泛型类型。

相反,pyright 似乎只是“泄漏”通用变量。pyright 决定这样做可能有一个原则性的原因,但我忽略了这一点,但 IMO 这似乎是一个错误。


为了回答您的其他问题,您的示例程序是惯用的 Python,并且类型检查器理想情况下应该支持它而无需修改。

在有错误的行中添加# type: ignore注释是 PEP 484 认可的抑制错误消息的方式。我对 pyright 不够熟悉,不知道它是否有不同的首选方式来抑制错误。

于 2020-03-04T00:02:17.430 回答