我一直在向我的软件包的.py
文件添加类型信息,以支持针对软件包运行mypy
。除此之外,还可以为此第三方软件包生成typeshed信息。
由于我的包必须与Python 2.7兼容,我使用注释来获取类型信息:
def __init__(self, s):
# type: (Text) -> None
但是为了运行mypy
,这需要我导入输入:
from typing import Text, IO, BinaryIO, Union
这会导致两个问题:
这不适用于Python 3.5.0和3.5.1,因为它有一个模块typing
但不包含Text
。从PyPI安装typing
并没有解决这个问题。 (并且有些用户在该版本的Python上运行该软件包。)
这使得我的软件包依赖typing
进行2.7 / 3.3 / 3.4安装,需要额外的下载和安装。
我定义了自己的Union
类型:
StreamType = Union[BinaryIO, IO[str], StringIO]
StreamTextType = Union[Text, StreamType]
根据可用或不可用的类型,必须有条件地执行此代码。
对于第一个问题,由于我没有在Python 3.5.0 / 1下运行mypy
,我可以做类似的事情:
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
时执行import语句?
针对环境变量进行测试还可以让我将自己类型的定义放在#34; guarded&#34;。
或其他一些解决方案?
答案 0 :(得分:5)
与mypy
关联的唯一环境变量是MYPYPATH
,它由包的代码读取,而不是由它设置。虽然可能会设置MYPYPATH
(特别是在生成typeshed
信息时,要提供&#34;其他&#34;类型信息),但不能保证它是。
您无法注释掉import
语句,但可以将其放在一个永不执行的块中:
if False: # MYPY
from typing import Text, IO, BinaryIO, Union
这样做的好处是,您不必导入os
来获取环境变量(和/或sys
以获取version_info
)在您的特定Python文件中没有其他需要。
您的类型定义也应该像这样指定,并且可以在导入或定义所有使用的类型后的任何地方出现:
# 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
如果您要在Python 2.7环境中运行typing
,您可能仍需要安装mypy
,但普通软件包的用户不会受此影响。
请注意,我在每个块的# MYPY
之后添加了评论if
。搜索from typing
的文件很简单,但如果StreamType
更改其行为并且您的代码需要进行调整,那么mypy
的块就不会那么容易找到。