sys.version_info是什么类型?

时间:2019-09-09 22:58:29

标签: python python-typing

如何在以下函数中添加类型注释?

import sys

def f(info):
    return info.major

f(sys.version_info)

使用pyannotate表示应该为:

import sys

def f(info):
    # type: (sys.version_info) -> int
    return info.major

f(sys.version_info)

但是mypy抱怨:

$ mypy test.py
test.py:10: error: Variable "sys.version_info" is not valid as a type
test.py:12: error: sys.version_info? has no attribute "major"```

sys.version_info的类型似乎是它本身:

>>> import sys
>>> type(sys.version_info)

它看起来像NamedTuple,但是如果有这样的注释:

from typing import NamedTuple

VersionInfo = NamedTuple(
    'sys.version_info', [
        ('major', int),
        ('minor', int),
        ('micro', int),
        ('releaselevel', str),
        ('serial', int)
    ]
)

import sys

def f(info):
    # type: (VersionInfo) -> int
    return info.major

f(sys.version_info)

mypy检查仍然失败:

$ mypy test.py
test.py:25: error: Argument 1 to "f" has incompatible type "_version_info"; expected "sys.version_info@9"

1 个答案:

答案 0 :(得分:2)

为了找到某种标准库函数的类型,您应该查看Typeshed,这是标准库的类型提示存储库+选择第3方模块。

在这种情况下,我们可以看到sys.version_infoannotated as being of type sys._version_info,它是伪造的,合成的纯类型类,它是Tuple[int, int, int, str, int]的子类。

您还可以通过针对以下程序运行mypy来亲自验证:

import sys
reveal_type(sys.version_info)

这将产生以下输出-请注意回退:

 Revealed type is 'Tuple[builtins.int, builtins.int, builtins.int, builtins.str, builtins.int, fallback=sys._version_info]'

因此,要注释功能,您有几种选择。首先,您可以使用此仅类型检查类-您只需要确保从不导入/在运行时引用它即可。

如果您使用类型注释语法(例如# type: (sys._version_info) -> int),则此问题已为您解决。毕竟,注释中的代码片段永远不会在运行时进行评估。

但是,如果您想使用Python-3样式类型注释,则可以执行以下操作:

from __future__ import annotations
import sys

def f(info: sys._version_info) -> int:
    return info.major

f(sys.version_info)

__future__导入基本上使上面的程序等效于下面的程序-所有类型提示都被视为字符串,因此不需要在运行时进行评估:

import sys

def f(info: "sys._version_info") -> int:
    return info.major

f(sys.version_info)

或者,如果要在没有sys模块名称空间的情况下显式导入类型,也可以执行以下操作:

from __future__ import annotations
from typing import TYPE_CHECKING
import sys

# Doing just 'if False:' also works
if TYPE_CHECKING:
    from sys import _version_info as VersionInfo

def f(info: VersionInfo) -> int:
    return info.major

f(sys.version_info)