52

我正在尝试 Pythontyping模块。

我知道指定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。此外,目前无法以这种方式使用模块指定Sequence长度。typing

4

4 回答 4

40

你不能。列表是可变的、可变长度的结构。如果您需要固定长度的结构,请改用元组:

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

对于固定长度的数据结构,列表只是错误的数据类型。

于 2017-06-29T19:53:40.367 回答
12

到目前为止,只有元组支持指定固定数量的字段,并且没有固定重复次数的捷径。

这是打字模块的定义和文档字符串:

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)

由于列表是可变的、可变长度的类型,因此使用类型声明来指定固定大小没有任何意义。

于 2017-06-29T19:53:28.503 回答
9

Annotated在这里可以派上用场。它允许您指定任意元数据来输入提示:

Annotated[List[float], 3]
于 2021-04-18T09:16:39.757 回答
4

当也遇到同样的问题时,我很不高兴看到Martijn Pieters 的回答。因为我想要一种“快速”和“简单”的方法来解决这个问题。

所以我首先尝试了这里列出的其他建议。

注意:我使用 VSCode 和 Pylance 作为语言服务器

Zaffys 的回答是我最喜欢的

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 receiveda, 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

但就像 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 是一个很棒的想法——让我们做更多的事情!

于 2021-05-11T10:23:41.067 回答