2

我一直在向我的包.py文件添加类型信息,以支持mypy针对包运行。除其他外,还允许为此第三方包生成类型信息。

由于我的包必须与 Python 2.7 兼容,因此我对类型信息使用注释:

def __init__(self, s):
    # type: (Text) -> None

但为了运行mypy这需要我导入输入:

from typing import Text, IO, BinaryIO, Union

这会导致两个问题:

  1. 这不适用于 Python 3.5.0 和 3.5.1,因为它有一个模块typing,但不包括Text. 从 PyPI安装typing并不能解决这个问题。(并且有些用户在该版本的 Python 上运行该包)。

  2. 这使我的包依赖于typing2.7/3.3/3.4 安装,需要额外的下载和安装。

  3. Union定义了自己的类型:

    StreamType = Union[BinaryIO, IO[str], StringIO]
    StreamTextType = Union[Text, StreamType]
    

    必须根据输入是否可用,有条件地执行此代码。

对于第一个问题,由于我不在mypyPython 3.5.0/1 下运行,我可以执行以下操作:

import sys
if sys.version_info < (3, 5, 0) and sys.version_info >= (3, 5, 2):
    from typing import Text, IO, BinaryIO, Union

但这并不能解决第二个问题。

注释掉import,例如注释中的类型信息,

# from typing import Text, IO, BinaryIO, Union

会导致mypy抛出错误Name 'Text' is not defined

第三个问题可以通过使用try- except(丑陋,而且可能效率低下)或例如通过测试环境变量(也可以用来解决第一个问题)来解决。

运行时是否设置了环境变量mypy,我可以对其进行测试,以便仅在运行时执行导入语句mypy?针对环境变量进行测试还可以让我将自己类型的定义放在“受保护的”范围内。

还是其他解决方案?

4

1 回答 1

5

唯一关联的环境变量mypyis MYPYPATHand that 由包的代码读取,而不是由它设置。尽管MYPYPATH可能已设置(尤其是在生成typeshed信息时,以提供“其他”类型的信息),但不能保证它是。

您不能注释掉该import语句,但您可以将它放在一个从不执行的块中:

if False:  # MYPY
    from typing import Text, IO, BinaryIO, Union

这样做的好处是,如果您在特定的 Python 文件中没有其他需要,则无需导入os即可获取环境变量(和/或sys获取)。version_info

你的类型定义也应该这样指定,并且可以在所有使用的类型被导入或定义后的任何地方发生:

# import or define StringIO

if False:  # MYPY
    StreamType = Union[BinaryIO, IO[str], StringIO]
    StreamTextType = Union[Text, StreamType]

如果上述内容在 中mytypes.py,则包中的任何其他源文件(StreamTypeText在任何类型定义中使用)都应该执行以下操作:

if False:  # MYPY
    from typing import Text, IO, BinaryIO, Union
    from .mytypes StreamType

以上将满足mypy,因此Text不会在未定义时引发错误。它也可以在 3.5.0/1 上运行,并且不需要让你的包依赖于typing

typing如果您要在 Python 2.7 环境中运行,您可能仍然需要安装mypy,但您的普通包的用户不会受此影响。

请注意,我在每个块# MYPY之后添加了注释。if搜索文件from typing很容易,但是如果不改变其行为并且您的代码需要调整StreamType,则不会那么容易找到带有的块。mypy

于 2017-04-20T10:21:49.160 回答