mypy:如何解决这个元组混淆
mypy: How to solve this tuple confusion
Python 3.6没问题这个元组样例:
# tpl is a tuple. Each entry consists of a tuple with two entries. The first
# of those is a tuple of two strings. The second one is a tuple of tuples with
# three strings.
tpl = (
(('a', 'b'), (('1', '2', '3'), ('4', '5', '6'))),
(('c', 'd'), (('7', '8', '9'),)),
)
for first_tuple, second_tuple in tpl:
str1, str2 = first_tuple
print(str1, str2)
for str1, str2, str3 in second_tuple:
print(' ', str1, str2, str3)
print()
输出:
a b
1 2 3
4 5 6
c d
7 8 9
但是mypy 0.511好像有点乱,报错:
ttpl.py:13: error: Iterable expected
ttpl.py:13: error: "object" has no attribute "__iter__"; maybe "__str__"?
我能做些什么来帮助 mypy 了解发生了什么?
mypy 默认将元组视为元组,而不是序列 (Tuple[T, ...]
)。当您迭代具有不兼容类型的元组时,变量的类型被确定为 object
:
for x in ((1,), (2, 3)):
reveal_type(x)
for y in x:
pass
您可以提供合适的、非常漂亮的类型提示:
from typing import Tuple
tpl: Tuple[Tuple[Tuple[str, str], Tuple[Tuple[str, str, str], ...]], ...] = (
(('a', 'b'), (('1', '2', '3'), ('4', '5', '6'))),
(('c', 'd'), (('7', '8', '9'),)),
)
代表真实数据格式的类型别名可能会有所帮助。
虽然 给出了 python 3.6 的正确答案,也让我了解了正在发生的事情,但我想指出两种可能的选择:
如果您仍然需要使用没有 PEP 526(变量注释的语法)的 python 版本,您可以这样做:
from typing import Tuple, Iterable
TypeOfData = Iterable[
Tuple[
Tuple[str, str],
Iterable[Tuple[str, str, str]]
]
]
tpl = (
(('a', 'b'), (('1', '2', '3'), ('4', '5', '6'))),
(('c', 'd'), (('7', '8', '9'),)),
) # type: TypeOfData
for first_tuple, second_tuple in tpl:
str1, str2 = first_tuple
print(str1, str2)
for str1, str2, str3 in second_tuple:
print(' ', str1, str2, str3)
print()][1]
如果只是想让mypy不报错,也可以:
tpl = (
(('a', 'b'), (('1', '2', '3'), ('4', '5', '6'))),
(('c', 'd'), (('7', '8', '9'),)),
)
for first_tuple, second_tuple in tpl:
str1, str2 = first_tuple
print(str1, str2)
for str1, str2, str3 in second_tuple: # type: ignore
print(' ', str1, str2, str3)
print()
Python 3.6没问题这个元组样例:
# tpl is a tuple. Each entry consists of a tuple with two entries. The first
# of those is a tuple of two strings. The second one is a tuple of tuples with
# three strings.
tpl = (
(('a', 'b'), (('1', '2', '3'), ('4', '5', '6'))),
(('c', 'd'), (('7', '8', '9'),)),
)
for first_tuple, second_tuple in tpl:
str1, str2 = first_tuple
print(str1, str2)
for str1, str2, str3 in second_tuple:
print(' ', str1, str2, str3)
print()
输出:
a b
1 2 3
4 5 6
c d
7 8 9
但是mypy 0.511好像有点乱,报错:
ttpl.py:13: error: Iterable expected
ttpl.py:13: error: "object" has no attribute "__iter__"; maybe "__str__"?
我能做些什么来帮助 mypy 了解发生了什么?
mypy 默认将元组视为元组,而不是序列 (Tuple[T, ...]
)。当您迭代具有不兼容类型的元组时,变量的类型被确定为 object
:
for x in ((1,), (2, 3)):
reveal_type(x)
for y in x:
pass
您可以提供合适的、非常漂亮的类型提示:
from typing import Tuple
tpl: Tuple[Tuple[Tuple[str, str], Tuple[Tuple[str, str, str], ...]], ...] = (
(('a', 'b'), (('1', '2', '3'), ('4', '5', '6'))),
(('c', 'd'), (('7', '8', '9'),)),
)
代表真实数据格式的类型别名可能会有所帮助。
虽然
如果您仍然需要使用没有 PEP 526(变量注释的语法)的 python 版本,您可以这样做:
from typing import Tuple, Iterable
TypeOfData = Iterable[
Tuple[
Tuple[str, str],
Iterable[Tuple[str, str, str]]
]
]
tpl = (
(('a', 'b'), (('1', '2', '3'), ('4', '5', '6'))),
(('c', 'd'), (('7', '8', '9'),)),
) # type: TypeOfData
for first_tuple, second_tuple in tpl:
str1, str2 = first_tuple
print(str1, str2)
for str1, str2, str3 in second_tuple:
print(' ', str1, str2, str3)
print()][1]
如果只是想让mypy不报错,也可以:
tpl = (
(('a', 'b'), (('1', '2', '3'), ('4', '5', '6'))),
(('c', 'd'), (('7', '8', '9'),)),
)
for first_tuple, second_tuple in tpl:
str1, str2 = first_tuple
print(str1, str2)
for str1, str2, str3 in second_tuple: # type: ignore
print(' ', str1, str2, str3)
print()