简体   繁体   English

使用 Python 输入模块指定序列或列表的长度

[英]Specify length of Sequence or List with Python typing module

I'm giving the Python typing module a shot.我正在尝试使用 Python typing模块。

I know that it's valid to specify the length of a List like the following*:我知道像下面这样指定List的长度是有效的*:

List[float, float, float]   # List of 3 floats <-- NOTE: this is not valid Python

Is there any shorthand for longer lists?是否有更长列表的简写? What if I want to set it to 10 floats?如果我想将它设置为 10 个浮点数怎么办?

List[float * 10]   # This doesn't work.

Any idea if this is possible, this would be handy.任何想法,如果这是可能的,这会很方便。


*NOTE: It turns out that supplying multiple arguments to Sequence[] (and its subclasses) in this manner is currently NOT valid Python. *注意:事实证明,以这种方式向Sequence[] (及其子类)提供多个参数目前不是有效的 Python。 Furthermore, it is currently not possible to specify a Sequence length using the typing module in this way.此外,目前无法以这种方式使用typing模块指定Sequence长度。

You can't.你不能。 A list is a mutable, variable length structure.列表是可变的、可变长度的结构。 If you need a fixed-length structure, use a tuple instead:如果您需要固定长度的结构,请改用元组:

Tuple[float, float, float, float, float, float, float, float, float, float]

Or better still, use anamed tuple , which has both indices and named attributes:或者更好的是,使用具有索引和命名属性的命名元组

class BunchOfFloats(NamedTuple):
    foo: float
    bar: float
    baz: float
    spam: float
    ham: float
    eggs: float
    monty: float
    python: float
    idle: float
    cleese: float

A list is simply the wrong data type for a fixed-length data structure.列表只是固定长度数据结构的错误数据类型。

So far, only tuples support specifying a fixed number of fields and it has no short-cut for a fixed number of repetitions.到目前为止,只有元组支持指定固定数量的字段,并且没有固定数量重复的捷径。

Here's the definition and docstring from thetyping module:这是来自打字模块的定义和文档字符串:

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)

Since lists are a mutable, variable-length type, it doesn't make any sense to use a type declaration to specify a fixed size.由于列表是可变的、可变长度的类型,因此使用类型声明来指定固定大小没有任何意义。

Annotated can be handy here.在这里Annotated可以很方便。 It allows you to specify arbitrary metadata to type hints:它允许您指定任意元数据来键入提示:

Annotated[List[float], 3]

Please see documentation for more information.有关更多信息,请参阅 文档

When also confronted with the same problem, I was not happy seeing Martijn Pieters answer .当也遇到同样的问题时,看到Martijn Pieters 的回答让我很不高兴。 Since I wanted a "fast" and "easy" way to solve this problem.因为我想要一种“快速”和“简单”的方法来解决这个问题。

So I tried the other suggestions listed here first.所以我首先尝试了这里列出的其他建议。

Note: I used VSCode with Pylance as Language Server注意:我使用 VSCode 和 Pylance 作为语言服务器

Zaffys answer was my favorite Zaffys的回答是我最喜欢的

def demystify(mystery: Annotated[Tuple[int], 6]):
    a, b, c, d, e, f = mystery
    print(a, b, c, d, e, f)

Hint for the function then looks like this: demystify: (mystery: Tuple[int]) -> None Also I get a Pylance Error Tuple size mismatch: expected 6 but received for the line a, b, c, d, e, f = mystery该函数的提示如下所示: demystify: (mystery: Tuple[int]) -> None另外我得到一个 Pylance 错误Tuple size mismatch: expected 6 but receiveda, b, c, d, e, f = mystery

Next I tried Tuple[6 * (int, )] which was mentioned by balu in the comments of Martijn Pieters answer接下来我尝试了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)

Resulting in the same Pylance Error as before.导致与以前相同的 Pylance 错误。 Hint for the function was this: demystify: (mystery: Tuple[Tuple[Type[int], ...]]) -> None该函数的提示是这样的: demystify: (mystery: Tuple[Tuple[Type[int], ...]]) -> None

Going back to writing down the expected length:回到写下预期长度:

def demystify(mystery: Tuple[int, int, int, int, int, int]):
    a, b, c, e, f, g = mystery
    print(a, b, c, e, f, g)

This resolved the Pylance Error, and got me a "clear" function hint: demystify: (mystery: Tuple[int, int, int, int, int, int]) -> None这解决了 Pylance 错误,并给了我一个“清晰”的函数提示: demystify: (mystery: Tuple[int, int, int, int, int, int]) -> None

But just like John Brodie, I was not happy with this solution.但就像 John Brodie 一样,我对这个解决方案并不满意。

Now back to the, at first, unwanted answer:现在回到最初不需要的答案:

class MysteryType(NamedTuple):
    a: int
    b: int
    c: int
    d: int
    e: int
    f: int
    g: int

def demystify(mystery: MysteryType):
    print(*mystery)

The function hint now seems more mystic: demystify: (mystery: MysteryType) -> None but creating a new MysteryType gives me all the information I need: (a: int, b: int, c: int, d: int, e: int, f: int, g: int)函数提示现在看起来更神秘: demystify: (mystery: MysteryType) -> None但是创建一个新的 MysteryType 给了我我需要的所有信息: (a: int, b: int, c: int, d: int, e: int, f: int, g: int)

Also I can use the MysteryType in other methods and functions without the need of counting the type hints.此外,我可以在其他方法和函数中使用 MysteryType,而无需计算类型提示。

So, to make a long story short and paraphrase the Zen of Python:因此,长话短说并转述 Python 之禅:

NamedTuples are one honking great idea -- let's do more of those! NamedTuples 是一个很棒的想法——让我们做更多这样的事情!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM