使用 Python 输入模块指定序列或列表的长度
Posted
技术标签:
【中文标题】使用 Python 输入模块指定序列或列表的长度【英文标题】:Specify length of Sequence or List with Python typing module 【发布时间】:2017-12-03 16:01:40 【问题描述】:我正在尝试 Python typing
模块。
我知道指定List
的长度是有效的,如下所示*:
List[float, float, float] # List of 3 floats <-- NOTE: this is not valid Python
有没有长列表的简写?如果我想将其设置为 10 个浮点数怎么办?
List[float * 10] # This doesn't work.
如果可能的话,这会很方便。
*注意:事实证明,以这种方式向Sequence[]
(及其子类)提供多个参数当前不是有效的 Python。此外,目前无法以这种方式使用typing
模块指定Sequence
长度。
【问题讨论】:
【参考方案1】:到目前为止,只有元组支持指定固定数量的字段,并且没有固定重复次数的捷径。
这是来自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)
由于列表是可变的、可变长度的类型,因此使用类型声明来指定固定大小没有任何意义。
【讨论】:
谢谢雷蒙德,够清楚了。虽然我在这里收到的两个答案都是准确和清晰的,但我仍然不能 100% 确定提示真正需要设置长度序列输入的函数的最佳方式。我想把它放在文档字符串中并不算太糟糕,但这似乎是一种耻辱。 (我真的很喜欢 PyCharm 如何在为每种方法生成的帮助中获取这些提示) "到目前为止..." 是否有计划在某个时候在typing
模块中指定一个固定长度、可变的序列Generic
?【参考方案2】:
你不能。列表是一个可变的、可变长度结构。如果您需要固定长度的结构,请改用元组:
Tuple[float, float, float, float, float, float, float, float, float, float]
或者更好的是,使用named tuple,它同时具有索引和命名属性:
class BunchOfFloats(NamedTuple):
foo: float
bar: float
baz: float
spam: float
ham: float
eggs: float
monty: float
python: float
idle: float
cleese: float
对于固定长度的数据结构,列表只是错误的数据类型。
【讨论】:
如果你使用的是元组,你也可以使用文字省略号,即Tuple[int, ...]
PEP484
@TomaszBartkowiak:这与所要求的内容相反。是的,您可以通过这种方式声明一个包含单一类型的可变长度元组。但这不是固定大小。
有时您需要一个固定长度的可变容器。例如。如果要将容器项初始化为 None,然后使用新值更新这些项。但容器的大小仍将保持固定。
@Matt:当然,但是没有内置的 Python 类型可以让你这样做,所以也没有类型提示。
仅供参考 @MartijnPieters 的第一个建议可以缩写为 Tuple[10 * (float, )]
,我觉得它相当简洁,因为它非常清楚地表达了它的目的。【参考方案3】:
Annotated
在这里可以派上用场。它允许您指定任意元数据来输入提示:
Annotated[List[float], 3]
【讨论】:
【参考方案4】:当我也遇到同样的问题时,看到Martijn Pieters answer 我很不高兴。因为我想要一种“快速”和“简单”的方法来解决这个问题。
所以我先尝试了这里列出的其他建议。
注意:我使用 VSCode 和 Pylance 作为语言服务器
Zaffys answer 是我的最爱
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
我还收到了 Tuple size mismatch: expected 6 but received
行 a, b, c, d, e, f = mystery
的 Pylance 错误
接下来我尝试了Tuple[6 * (int, )]
,这是balu在Martijn Pieters answer的cmets中提到的
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
但就像 John Brodie 一样,我对这个解决方案并不满意。
现在回到最初不想要的答案:
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 是一个非常棒的想法——让我们做更多这样的事情!
【讨论】:
以上是关于使用 Python 输入模块指定序列或列表的长度的主要内容,如果未能解决你的问题,请参考以下文章
python 如何生成 2 1 4 3 6 5 8 7。。。的指定长度的序列?