我知道指定
List
的长度是无效的,如下所示:
List[float, float, float] # List of 3 floats
或:
List[float * 10] # List of 10 floats
这可能吗?
你不能。列表是可变的、可变长度结构。如果您需要固定长度的结构,请使用元组:
Tuple[float, float, float, float, float, float, float, float, float, float]
或者更好的是,使用命名元组,它既有索引也有命名属性:
class BunchOfFloats(NamedTuple):
foo: float
bar: float
baz: float
spam: float
ham: float
eggs: float
monty: float
python: float
idle: float
cleese: float
列表对于固定长度的数据结构来说是错误的数据类型。
typing.Annotated
在这里可以很方便。它允许您指定任意元数据来键入提示:
Annotated[list[float], 3]
刚接触
Annotated
? 这是文档的片段:
如果库(或工具)遇到类型提示
并且对于元数据没有特殊逻辑Annotated[T, x]
,它应该忽略它并简单地将类型视为x
。T
值得注意的是,
mypy
对于此类事情有一个“未完成的请求”(截至 2022 年 11 月开放)。 同时,将 Annotated
视为开发人员的可读性,而不是自动检查(除非您开发检查工具)。这是来自
typing 模块的定义和文档字符串:
class Tuple(tuple, extra=tuple, metaclass=TupleMeta):
"""Tuple type; Tuple[X, Y] is the cross-product type of X and Y.
Example: Tuple[T1, T2] is a tuple of two elements corresponding
to type variables T1 and T2. Tuple[int, float, str] is a tuple
of an int, a float and a string.
To specify a variable-length tuple of homogeneous type, use Tuple[T, ...].
"""
__slots__ = ()
def __new__(cls, *args, **kwds):
if _geqv(cls, Tuple):
raise TypeError("Type Tuple cannot be instantiated; "
"use tuple() instead")
return _generic_new(tuple, cls, *args, **kwds)
由于列表是可变的、可变长度的类型,因此使用类型声明来指定固定大小没有任何意义。
。因为我想要一个“快速”和“简单”的方法来解决这个问题。 所以我首先尝试了这里列出的其他建议。
注意:我使用 VSCode 和 Pylance 作为语言服务器
Zaffy 的回答是我最喜欢的
def demystify(mystery: Annotated[Tuple[int], 6]):
a, b, c, d, e, f = mystery
print(a, b, c, d, e, f)
该函数的提示如下所示:
demystify: (mystery: Tuple[int]) -> None
另外,我还收到了 Pylance 错误
Tuple size mismatch: expected 6 but received
行 a, b, c, d, e, f = mystery
接下来我尝试了Tuple[6 * (int, )]
,这是balu在
Martijn Pieters回答的评论中提到的
def demystify(mystery: Tuple[6 * (int,)]):
a, b, c, e, f, g = mystery
print(a, b, c, e, f, g)
导致与之前相同的 Pylance 错误。 该功能的提示是这样的:
demystify: (mystery: Tuple[Tuple[Type[int], ...]]) -> None
回到写下预期长度:
def demystify(mystery: Tuple[int, int, int, int, int, int]):
a, b, c, e, f, g = mystery
print(a, b, c, e, f, g)
这解决了 Pylance 错误,并给了我一个“清晰”的功能提示:
demystify: (mystery: Tuple[int, int, int, int, int, int]) -> None
但就像约翰·布罗迪一样,我对这个解决方案并不满意。
现在回到最初不需要的答案:
class MysteryType(NamedTuple):
a: int
b: int
c: int
d: int
e: int
f: int
g: int
def demystify(mystery: MysteryType):
print(*mystery)
函数提示现在看起来更加神秘:
demystify: (mystery: MysteryType) -> None
,但是创建一个新的 MysteryType 为我提供了我需要的所有信息:
(a: int, b: int, c: int, d: int, e: int, f: int, g: int)
我还可以在其他方法和函数中使用 MysteryType,而无需计算类型提示。
所以,长话短说,解释一下 Python 的禅宗:
NamedTuples 是一个非常棒的想法——让我们做更多这样的事情!