如何键入可以获取列表或元组的列表或元组的函数?

Posted

技术标签:

【中文标题】如何键入可以获取列表或元组的列表或元组的函数?【英文标题】:How to type a function that can take a list or tuple of a list or tuple? 【发布时间】:2019-11-18 14:43:27 【问题描述】:

我正在尝试定义一个函数,该函数可以接收对象容器的容器,并且我不在乎容器是元组还是列表。

(我知道我可以经历实现this 的麻烦,但我不想这样做,我仍然不确定这是否能解决我的问题。)

所以,我有以下代码:

from typing import Any, Union, List, Tuple

# (list or tuple) of Any
AnyBucket = Union[List[Any], Tuple[Any, ...]]
# should be (list or tuple) of (lists or tuples) of Any
AnyBuckets = Union[List[AnyBucket], Tuple[AnyBucket, ...]]

def takes_any_buckets(inpt: AnyBuckets) -> None:
    print(inpt[0][0])

input_value: List[List[Any]] = [[1], [2]]

# Argument 1 to "takes_any_buckets" has incompatible type "List[List[Any]]";
# expected "Union[List[Union[List[Any], Tuple[Any, ...]]], Tuple[Union[List[Any], Tuple[Any, ...]], ...]]"
takes_any_buckets(input_value)

我有两个问题:

    为什么 Mypy 会为此抛出错误? 我可以做些什么来获得我想要的功能(没有出现 Mypy 错误)?

(我不想只用# type: ignore 禁用错误,我想定义一个可以工作的类型。)

我对 (1) 的猜测是它与 Lists 是 invariant 有关,但是对于这个复杂的示例,我不知道如何。

除了可能实施前面提到的麻烦之外,我对 (2) 没有任何想法,这将使我摆脱 Unions,我怀疑这可能是问题的一部分。

【问题讨论】:

如果您对tuplelist 都满意,是否有理由不接受typing.Sequence(涵盖两者)或typing.Container(更广泛一点,接受非-像set)这样的可索引类型? 谢谢;在过去的几分钟里,我自己发现了 Sequence(适用于我的情况)。如果您写它作为问题(2)的答案,我会暂时接受。 【参考方案1】:
    确实与列表不变有关。当前版本的 Mypy 会告诉你这一点;如果您在当前版本中运行代码,则会收到以下注释以及错误:
main.py:14: note: "List" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance
main.py:14: note: Consider using "Sequence" instead, which is covariant

列表不变意味着A 类型的事物列表是B 类型的事物列表的子类型当且仅当A 等于B .这意味着即使 A 是 B 的子类型List[A] 也不是 List[B] 的子类型。 (有关不变性的解释以及 mypy 将列表视为不变的原因,请参见此处:https://mypy.readthedocs.io/en/stable/generics.html#variance-of-generic-types)。

所以List[List[Any]] 不是List[AnyBucket] 的子类型,即使List[Any]AnyBucket 的子类型,所以input_value 没有与AnyBuckets 兼容的类型。因此出现错误。

    正如上面的 Mypy 和 ShadowRanger 都建议的那样,您可能应该使用 Sequence,这是一种协变类型,它涵盖了可以被索引到的可迭代对象(第一个近似值 - 对于集合,还有一些其他的事情需要是真实的因为它是一个序列)。您需要从 collections.abc 导入它;看这里:https://docs.python.org/3/library/collections.abc.html#collections.abc.Sequence

我说“可能”是因为这完全取决于您要键入的函数对集合的作用。例如,如果您所做的只是遍历集合(一次),那么您想使用Iterable,这是一种更通用的类型。

使用Sequence 之类的一个优点是,如果有任何其他类型的对象漂浮在那里——也许是用户定义的——可以完成你想要的工作,它们将是你函数的有效输入(只要他们已经注册为Sequences)。一般来说,如果你可以使用structural typing,那就很好了,它是duck-typing 的静态类型版本,相当于 Python 方式。

【讨论】:

以上是关于如何键入可以获取列表或元组的列表或元组的函数?的主要内容,如果未能解决你的问题,请参考以下文章

Python基础(3) - 去掉列表或元组中的重复元素

使用参数列表或元组在 pandas 中读取 SQL

从元组的元组中创建一个列表

Python列表元组字典和字符串的常用函数

python 列表,字典,元组,字符串,常用函数

PYTHON 写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者