繁体   English   中英

Python 类型提示,可索引对象

[英]Python type-hinting, indexable object

我的函数需要接受一个对象,可以通过索引从中提取数据,即。 一个List或一个定义了__getitem__方法的实例。

我可以使用哪种类型来提示这个参数?

更新:据我所知,目前没有这种类型,我尝试自己制作一个:

class IndexableContainer(Generic[int, ReturnType]):
    def __getitem__(self, key: int) -> ReturnType:
        ...

但我收到以下错误:

  File "indexable_container.py", line 22, in IndexableContainer
    class IndexableContainer(Generic[int, ReturnType]):
  File ".../lib/python3.6/typing.py", line 682, in inner
    return func(*args, **kwds)
  File ".../lib/python3.6/typing.py", line 1112, in __getitem__
    "Parameters to Generic[...] must all be type variables")
TypeError: Parameters to Generic[...] must all be type variables

我该怎么做?

有几种不同的方法可以做到这一点。

如果您只使用自定义类(您可以编写的)作为可索引容器,那么您需要做的就是调整您的代码并删除该“int”类型参数:

class IndexableContainer(Generic[ReturnType]):
    def __getitem__(self, key: int) -> ReturnType:
        ...

class MyCustomContainer(IndexableContainer[ReturnType]):
    def __getitem__(self, key: int) -> ReturnType:
        # Implementation here

def requires_indexable_container(container: IndexableContainer[ReturnType]) -> ReturnType:
    # Code using container here

当然,问题是,如果您想将一个普通的旧列表传递到函数中,您将无法这样做,因为 list 不会对您的自定义类型进行子类化。

我们也许可以通过巧妙地使用@overload装饰器和联合来对某些输入进行特殊处理,但是还有第二种方法,尽管是实验性的,称为Protocols

协议基本上允许您使用类型提示以一种理智的方式表达“鸭子类型”:基本思想是我们可以调整 IndexableContainer 以成为协议。 现在,任何使用适当签名实现__getitem__方法的对象都被视为有效的 IndexableContainer,无论它们是否子类化该类型。

唯一需要注意的是,协议目前是实验性的,(afaik)仅由 mypy 支持。 计划是最终将协议添加到通用 Python 生态系统中——具体提案参见PEP 544——但我没有跟踪讨论/不知道它的状态是什么。

在任何情况下,要使用协议,请使用 pip 安装typing_extensions模块。 然后,您可以执行以下操作:

from typing_extensions import Protocol

# ...snip...


class IndexableContainer(Protocol, Generic[ReturnType]):
    def __getitem__(self, key: int) -> ReturnType:
        ...

def requires_indexable_container_of_str(container: IndexableContainer[str]) -> None:
    print(container[0] + "a")

a = ["a", "b", "c"]
b = {0: "foo", 2: "bar"}
c = "abc"
d = [1, 2, 3]

# Type-checks
requires_indexable_container_of_str(a)
requires_indexable_container_of_str(b)
requires_indexable_container_of_str(c)

# Doesn't type-check
requires_indexable_container_of_str(d)

似乎我们能得到的最接近的是:

Mapping[int, Any]

虽然这不是我想要的,但已经足够接近了。

This answer to a related question建议typing.Sequence . typing.Sequence 这种类型同时支持__getitem____len__

然而,鉴于它目前已被弃用,我认为最好使用collections.abc.Sequence

然而,正如作者稍后在评论中提到的,他/她实际上也需要__delitem__东西,在这种情况下collections.abc.MutableSequence可能是最合适的(@Yuval 在评论中也提到了这一点)。 它支持所有__getitem____setitem____delitem____len__insert

最终类型的示例用法(改编自参考答案):

from collections.abc import MutableSequence

def foo(bar: MutableSequence[Any]):
    # bar is a mutable sequence of any objects

暂无
暂无

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

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