如何注释采用可变长度元组的函数? (可变元组类型注释)

Posted

技术标签:

【中文标题】如何注释采用可变长度元组的函数? (可变元组类型注释)【英文标题】:How to annotate function that takes a tuple of variable length? (variadic tuple type annotation) 【发布时间】:2019-07-11 20:03:18 【问题描述】:

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

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"))

当我像上面提到的那样注释函数时,我会收到这些错误消息

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]"

process_tuple 确实适用于元组,我将它们用作可变长度的不可变列表。我在网上没有找到关于这个话题的任何共识,所以我想知道我应该如何注释这种输入。

【问题讨论】:

您在运行代码时是否遇到这些错误?我运行代码没有任何错误。 我在运行 mypy 时遇到这些错误。 【参考方案1】:

我们可以像这样使用... 文字(又名Ellipsis)来注释可变长度的同构元组:

def process_tuple(t: Tuple[str, ...]):
    ...

之后,错误应该会消失。

来自docs:

要指定同构类型的变长元组,请使用字面量 省略号,例如Tuple[int, ...]。一个普通的Tuple 相当于 Tuple[Any, ...],然后转至tuple

【讨论】:

这实际上有点反直觉和反逻辑。如果我们假设List[str] 适用于可变长度列表,那么为什么Tuple[str] 不适用于可变长度元组?而(type(("a", "a")) == type(("a", "a", "a")) 产生True @Montreal:这是因为tuples 和lists 用于不同的目的:tuples 是异构容器(例如任意函数的位置参数或来自 RDBMS 的单个表记录,或在数学世界中——不同集合的笛卡尔积的元素(或笛卡尔积的联合),因此每个坐标可能有不同的类型,但它们的数量通常是固定的),而lists 是同质的(如集合相同的表记录或某些集合的有限元素序列) @Montreal: 所以Tuple[str] 是一个单一的str 对象tuple,而List[str] 是任意数量的str 对象的集合【参考方案2】:

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

from typing import Tuple


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

@overload
def process_tuple(t: Tuple[str, str]):
    ...

或与联盟:

from typing import Tuple, Union


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

【讨论】:

我知道它,但我的元组可能很长,所以它不是一个选项。无论如何,谢谢。 btw overloads 应该在实施之前进行

以上是关于如何注释采用可变长度元组的函数? (可变元组类型注释)的主要内容,如果未能解决你的问题,请参考以下文章

Python的列表和元组的区别

Python--基本的对象类型(元组_不可变的数据类型)

Python不可变对象元组(tuple)详解

数据类型

Python元组tuple(不可变)

如何通过使用可变模板参数来专门化元组的类模板?