Python 为支持 __getitem__ 的 类 输入提示

Python type hint for classes that support __getitem__

我想向函数添加类型提示,该函数将接受任何具有 __getitem__ 方法的对象。例如,在

def my_function(hasitems, locator):
    hasitems[locator]

我不想将 hasitems 限制为特定类型,例如 listdict。只要它支持 __getitem__,它就是 my_function 的适当参数。我怎样才能在没有不必要限制的情况下注释它的类型?

编辑:显然 PyCharm 可以在许多常见情况下推断出适当的提示,但在我的实际用例中却没有。我不能 post 代码,因为它是为了工作,而且我一直没能找到 PyCharm 失败的非专有最小示例。在任何情况下,原始问题都没有引用 PyCharm 并且它仍然是类型提示的有效用例。

这适用于字典和列表,但不适用于任何泛型:

from typing import Any, Mapping, Sequence, Union

def my_function(hasitems: Union[Mapping, Sequence], locator: Any) -> Any:
    return hasitems[locator]

听起来您基本上想定义自己的 abstract base class (abc)

按照上面的文档,您可以定义一个自定义 abc,它只指示 __getitem__ 的存在,但让我们使用一个预定义的作为示例。 Mapping abc 由 __getitem__ 和其他一些魔术方法组成。你可以在isinstance中使用abcs,但你也可以直接将它们用作类型注释:

def foo(bar: Mapping):
    pass

或者,使用 extended type hinting support of ABCs 甚至可以做一些你已经在其他答案中看到的奇特的事情:

def foo(bar: Mapping[Any, Any]):
    pass

如果您愿意为 typing 安装一个不太正式的扩展,typing-extensions, you can use a Protocol, which should be an implementation of PEP-0544:

from typing_extensions import Protocol
from typing import Any

class GetItem(Protocol):
    def __getitem__(self: 'Getitem', key: Any) -> Any: pass

class BadGetItem:
    def __getitem__(self, a: int, b: int) -> Any: pass

def do_thing(arg: GetItem):
    pass

do_thing(dict())  # OK
do_thing(BadGetItem())  # Fails with explanation of correct signature
do_thing(1)  # Fails