添加类型信息而不依赖于 typing 模块
adding type information without dependency on typing module
我一直在将类型信息添加到包的 .py
文件中,以支持 运行ning 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
来解决(丑陋,也可能效率低下)或例如通过针对环境变量进行测试(也可用于解决第一个问题)。
在 运行ning mypy
时是否设置了我可以测试的环境变量,以便仅在 运行ning mypy
时执行导入语句?
针对环境变量进行测试还允许我将自己的类型定义放在 "guarded".
中
或者其他一些解决方案?
与 mypy
关联的唯一环境变量是 MYPYPATH
,它由包的代码读取,而不是由它设置。尽管可能会设置 MYPYPATH
(尤其是在生成 typeshed
信息时,以提供 "other" 类型信息),但不能保证它确实如此。
你不能注释掉 import
语句,但是你 可以 把它放在一个永远不会执行的块中:
if False: # MYPY
from typing import Text, IO, BinaryIO, Union
这样做的好处是您不必导入 os
来获取环境变量(and/or 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 环境中 运行 mypy
,您可能仍然需要安装 typing
,但是您的普通软件包的用户不会受到影响那。
请注意,我在每个块的 if
之后添加了注释 # MYPY
。搜索 from typing
的文件很容易,但是 StreamType
的块将不会那么容易找到,以防 mypy
更改其行为并且您的代码需要调整。
我一直在将类型信息添加到包的 .py
文件中,以支持 运行ning 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
来解决(丑陋,也可能效率低下)或例如通过针对环境变量进行测试(也可用于解决第一个问题)。
在 运行ning mypy
时是否设置了我可以测试的环境变量,以便仅在 运行ning mypy
时执行导入语句?
针对环境变量进行测试还允许我将自己的类型定义放在 "guarded".
或者其他一些解决方案?
与 mypy
关联的唯一环境变量是 MYPYPATH
,它由包的代码读取,而不是由它设置。尽管可能会设置 MYPYPATH
(尤其是在生成 typeshed
信息时,以提供 "other" 类型信息),但不能保证它确实如此。
你不能注释掉 import
语句,但是你 可以 把它放在一个永远不会执行的块中:
if False: # MYPY
from typing import Text, IO, BinaryIO, Union
这样做的好处是您不必导入 os
来获取环境变量(and/or 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 环境中 运行 mypy
,您可能仍然需要安装 typing
,但是您的普通软件包的用户不会受到影响那。
请注意,我在每个块的 if
之后添加了注释 # MYPY
。搜索 from typing
的文件很容易,但是 StreamType
的块将不会那么容易找到,以防 mypy
更改其行为并且您的代码需要调整。