Riz*_*hiy 5 python type-hinting
我的函数需要接受一个对象,可以通过索引viz从中提取数据。一个List或限定的实例__getitem__方法。
提示该参数的类型可以使用哪种类型?
更新:据我了解,目前还没有这种类型,我试图自己做一个:
class IndexableContainer(Generic[int, ReturnType]):
def __getitem__(self, key: int) -> ReturnType:
...
Run Code Online (Sandbox Code Playgroud)
但是我收到以下错误:
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
Run Code Online (Sandbox Code Playgroud)
我该怎么办?
有几种不同的方法可以做到这一点。
如果您可以仅使用自定义类(您可以编写的)作为可索引容器,那么您需要做的就是调整您的代码并删除该“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
Run Code Online (Sandbox Code Playgroud)
当然,问题是,如果您想将一个普通的旧列表传递到函数中,您将无法这样做,因为 list 不会对您的自定义类型进行子类化。
我们也许可以通过巧妙地使用@overload装饰器和联合来对某些输入进行特殊处理,但是还有第二种方法,尽管是实验性的,称为Protocols。
协议基本上允许您使用类型提示以一种理智的方式表达“鸭子类型”:基本思想是我们可以调整 IndexableContainer 以成为协议。现在,任何实现__getitem__具有适当签名的方法的对象都被视为有效的 IndexableContainer,无论它们是否子类化该类型。
唯一需要注意的是,协议目前是实验性的,(afaik)仅由 mypy 支持。计划是最终将协议添加到通用 Python 生态系统中——请参阅PEP 544了解具体提案——但我没有跟踪讨论/不知道它的状态是什么。
无论如何,要使用协议,请typing_extensions使用 pip安装模块。然后,您可以执行以下操作:
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)
Run Code Online (Sandbox Code Playgroud)
对相关问题的回答表明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
Run Code Online (Sandbox Code Playgroud)