如何在python中注释需要可变长度元组的函数?

Mon*_*eal 4 python type-hinting python-3.x mypy

我有一个函数,将不同长度的元组作为参数:

from typing import Tuple


def process_tuple(t: Tuple[str]):
    # Do nasty tuple stuff

process_tuple(("a",))
process_tuple(("a", "b"))
process_tuple(("a", "b", "c"))

Run Code Online (Sandbox Code Playgroud)

当我注释上述函数时,出现这些错误消息

fool.py:9: error: Argument 1 to "process_tuple" has incompatible type "Tuple[str, str]"; expected "Tuple[str]"
fool.py:10: error: Argument 1 to "process_tuple" has incompatible type "Tuple[str, str, str]"; expected "Tuple[str]"
Run Code Online (Sandbox Code Playgroud)

process_tuple真正适用于元组,我将它们用作可变长度的不可变列表。我尚未在互联网上找到关于此主题的任何共识,因此我想知道该如何注释这种输入。

Bro*_*ark 14

Python 3.9+

使用tuple

def process_tuple(t: tuple[str, ...]):
    pass
Run Code Online (Sandbox Code Playgroud)

自 Python 3.9 起,typing.Tuple已弃用。状态的文档typing.Tuple

自 3.9 版起已弃用builtins.tuple现在支持[].

Python 3.8 及更早版本

如果您使用的是 Python 3.8 或更早版本,您仍然应该使用typing.Tuple

from typing import Tuple

def process_tuple(t: Tuple[str, ...]):
    pass
Run Code Online (Sandbox Code Playgroud)


Aza*_*kov 9

我们可以使用...文字(aka Ellipsis)来注释可变长度的同类元组

def process_tuple(t: Tuple[str, ...]):
    ...
Run Code Online (Sandbox Code Playgroud)

之后错误应该消失。

来自文档

要指定同构类型的变长元组,请使用文字省略号,例如Tuple[int, ...]。一个平原Tuple等同于Tuple[Any, ...],进而等同 于tuple

  • @Montreal:那是因为`tuple`s 和`list`s 用于不同的目的:`tuple`s 是异构容器(如任意函数的位置参数或来自 RDBMS 的单个表记录,或在数学世界中——不同集合的笛卡尔积(或笛卡尔积的并集),所以每个坐标可能有不同的类型,但它们的数量通常是固定的),而 `list` 是同构的(比如相同表记录的集合或有限序列的某些集合的元素) (12认同)
  • 这实际上 * 是 * 有点违反直觉和逻辑。如果我们假设`List[str]` 适用于变长列表,那么为什么`Tuple[str]` 不适用于变长元组?并且 `(type(("a", "a")) == type(("a", "a", "a"))` 产生 `True`。 (9认同)
  • @Montreal:所以`Tuple[str]` 是一个单一的`str` 对象`tuple`,而`List[str]` 是任意数量`str` 对象的集合 (3认同)
  • 是的,元组和列表通常用于不同的目的,但我认为许多 Python 程序员只有在很长一段时间后才会了解这个约定(如果有的话)。原因是这种差异不是由语言属性决定的,而是由习惯造成的,恕我直言,文档中没有足够突出地提到这一点。--- 我只知道文档中的一个地方:*元组...通常包含异构的元素序列。...列表...它们的元素通常是同质的。* https://docs.python.org/3/tutorial/datastructs.html#tuples-and-sequences (3认同)

Wol*_*lph 8

除了 Azat 发布的省略号答案之外,您还可以通过使用@typing.overload或使其更加明确typing.Union

from typing import Tuple


@overload
def process_tuple(t: Tuple[str]):
    # Do nasty tuple stuff

@overload
def process_tuple(t: Tuple[str, str]):
    ...
Run Code Online (Sandbox Code Playgroud)

或者与联盟:

from typing import Tuple, Union


def process_tuple(t: Union[Tuple[str], Tuple[str, str], Tuple[str, str, str]]):
    # Do nasty tuple stuff
Run Code Online (Sandbox Code Playgroud)

  • 我知道这一点,但我的元组可能非常长,所以这不是一个选择。不管怎样,谢谢你。 (2认同)