Python 类型提示,可索引对象 [英] Python type-hinting, indexable object

查看:42
本文介绍了Python 类型提示,可索引对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

My function needs to accept an object, from which data can be extracted by index, viz. a List or an instance with defined __getitem__ method.

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

Which type can I use for type hinting this argument?

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

Update: As I understand there are presently no such type, I tried to make one myself:

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

我该怎么做?

推荐答案

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

There are several different ways you can do this.

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

If you're ok with using only custom classes (that you can write) as indexable containers, all you need to do is to adapt your code and remove that 'int' type parameter:

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

当然,问题是,如果您想将一个普通的旧列表传递到函数中,您将无法这样做,因为列表不会继承您的自定义类型.

The issue is, of course, that if you wanted to pass in a plain old list into the function, you wouldn't be able to do so since list doesn't subclass your custom type.

我们也许可以通过巧妙地使用 @overload 装饰器和联合来特殊情况下的某些输入,但是还有第二种方法,尽管是实验性的,称为 协议.

We could maybe special-case certain inputs via clever use of the @overload decorator and unions, but there's a second, albeit experimental, way of doing this known as Protocols.

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

Protocols basically let you express "duck typing" in a sane way using type hints: the basic idea is that we can tweak IndexableContainer to become a protocol. Now, any object that implements the __getitem__ method with the appropriate signature is counted as a valid IndexableContainer, whether or not they subclass that type or not.

唯一的警告是协议目前是实验性的并且(afaik)仅由 mypy 支持.计划最终将协议添加到通用 Python 生态系统中——请参阅 PEP 544 对于具体的提案——但我没有跟踪讨论/不知道讨论的状态是什么.

The only caveat is that Protocols are currently experimental and (afaik) only supported by mypy. The plan is to eventually add protocols to the general Python ecosystem -- see PEP 544 for the specific proposal -- but I haven't kept track of the discussion/don't know what the status of that is.

无论如何,要使用协议,请使用 pip 安装 typing_extensions 模块.然后,您可以执行以下操作:

In any case, to use protocols, install the typing_extensions module using pip. Then, you can do the following:

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)

这篇关于Python 类型提示,可索引对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆