我在定义不可变列表类型时遇到一个奇怪的错误:
import sys
from re import split
from typing import Tuple, List, NewType
tokens = split("(d+.d+)", sys.argv[1])
# this works perfectly
# Tokens = NewType("Tokens", List[str])
# print(Tokens(tokens))
# this doesn't work ...
Tokens = NewType("Tokens", Tuple[str])
print(Tokens(tuple(tokens)))
这是我得到的错误:
> mypy main.py
main.py:13: error: Argument 1 to "Tokens" has incompatible type "Tuple[Union[str, Any], ...]"; expected "Tuple[str]"
Found 1 error in 1 file (checked 1 source file)
错误发生的原因
当使用tuple()
将列表转换为元组时,Python
或至少Mypy
不知道元组中元素的确切类型。因此,出现了错误。使用不同的方法将列表转换为元组会导致不同的Mypy错误:
token_x = tuple(tokens)
token_y = tuple(i for i in tokens)
token_z = (*tokens, )
main.py:15: error: Argument 1 to "Tokens" has incompatible type "Tuple[Union[str, Any], ...]"; expected "Tuple[str]"
main.py:16: error: Argument 1 to "Tokens" has incompatible type "Tuple[Union[str, Any], ...]"; expected "Tuple[str]"
main.py:17: error: Argument 1 to "Tokens" has incompatible type "Tuple[Any, ...]"; expected "Tuple[str]"
解决方案
import sys
from re import split
from typing import Tuple, List, NewType
tokens: List[str] = split("(d+.d+)", sys.argv[1]) # explicit annotation on here is great but not necessary
token_x = tuple(tokens)
token_y = tuple(i for i in tokens)
token_z = (*tokens,)
# this works perfectly
# Tokens = NewType("Tokens", List[str])
# print(Tokens(tokens))
# this doesn't work ...
Tokens = NewType("Tokens", Tuple[str, ...]) # explicitly annotate with Tuple[str, ...]
Tokens = NewType("Tokens", Sequence[str]) # or using Sequence[str], which is recommended by Mypy offical document
print(Tokens(token_x))
print(Tokens(token_y))
print(Tokens(token_z))
附录
相关问题:如何注释采用可变长度元组的函数?(可变元组类型注释(
Tuple[str, ...]
的含义:元组中所有元素的str, ...
表示为str
Mypy官方文件:https://mypy.readthedocs.io/en/stable/kinds_of_types.html#tuple-类型