首页 > 解决方案 > 为 Python (mypy) 声明外部类型

问题描述

我正在为嵌入 IronPython 的工具编写 Python 脚本。这个工具将一些它自己的变量注入到 IronPython 全局范围中,例如一个名为resources.

当我编写脚本时,我收到许多关于未定义变量的误报 linter 错误。

有没有办法为工具定义的变量抑制这些错误?

我正在寻找与打字稿定义文件(*.d.ts)等效的东西。我想告诉我的编辑这些变量存在,并且(可选地)它们的类型是什么,但不想初始化它们的值(因为这会覆盖工具提供的定义)。

我的一个想法是在我的脚本中选择性地初始化这些变量,这样它们只在它们不存在时才被初始化(因此不会在运行时覆盖工具的定义)。例如

if resources is None:
    resources = None  # type: (str) -> object

但这似乎不是最佳解决方案。

标签: pythonmypy

解决方案


归根结底,您需要以一种或另一种形式对 mypy 撒谎——问题归结为符合人体工程学和方便的这样做方式。

这样做最方便的方法可能是在一个单独的文件中定义你的额外内容并将它们全局导入到你的脚本中。您可以通过利用typing.TYPE_CHECKING变量来做到这一点,而不会真正污染您的环境——该变量在运行时始终为 False,但在类型检查时被视为 true。所以,你可能会做这样的事情:

from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from my_ironpython_globals import *

但是,确保没有人在运行时实际尝试使用自定义模块中的任何内容可能是一个好主意。确保这一点的一种方法是在存根文件中定义所有额外的变量/函数——存根文件是 Python 对 TypeScript 定义文件的模拟。

简而言之,在您的项目中创建一个以.pyi扩展名(而不是.py)结尾的文件并在那里定义所有内容。

如果您想查看存根文件的外观示例,请尝试查看typeshed,这是标准库和一些流行的 3rd 方库的存根存储库。(Mypy 附带一份 typeshed 副本)。如果你对这类事情感兴趣,他们的贡献指南有一个风格指南。

如果您想将新创建的存根作为可以 pip-install 和使用的 3rd 方模块分发,请创建一个包含您的类型提示的符合 PEP 561 的包。


您可以采取的另一种方法是使用您自己的自定义类型的排版。也就是说,克隆或分叉类型并修改文件,以便它们包含特定于 ironpython 的全局变量stdlib/*/builtins.pyi

然后,使用--custom-typeshed-dir标志调用 mypy:例如 do mypy --custom-typeshed-dir path/to/my/typeshed mycode

如果键入此标志序列变得乏味,请创建一个配置文件并在那里对您的设置进行编码。

这种方法比第一种方法更有原则,因为您正在教 mypy 合法地识别任何可用的全局变量。然而,必须维护自己的分叉类型+跟上上游的变化很多工作(而且这种碎片可能并不理想)。

因此,如果您确实决定采用这种方法,可能值得先讨论一下 typeshed 的问题跟踪器。Typeshed(和 PEP 484 生态系统)总体上还是相当新的,因此仍有空间影响它的发展方向。


推荐阅读