如何在以下函数中添加类型注释?
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"
答案 0 :(得分:2)
为了找到某种标准库函数的类型,您应该查看Typeshed,这是标准库的类型提示存储库+选择第3方模块。
在这种情况下,我们可以看到sys.version_info
是annotated 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)