如何键入提示实例级函数(即不是方法)?

How to type hint an instance-level function (i.e. not a method)?

实例属性通常是 class 上的 annotated:

class Foo:
    x: int

    def __init__(self, x):
        self.x = x

Foo(0).x

这有效并且 mypy 没有报告任何问题。但是,当实例属性是 Callable 时,mypy 开始抱怨:

from typing import Callable


class Foo:
    func: Callable[[], int]

    def __init__(self, func):
        self.func = func


Foo(lambda: 0).func()

我收到以下错误:

test.py:11: error: Attribute function "func" with type "Callable[[], int]" does not accept self argument
Found 1 error in 1 file (checked 1 source file)

由于这个函数没有在class上定义,而是只存储在实例字典中,在属性查找期间它不会绑定到实例(简而言之:上面的代码片段有效)。所以我不明白为什么 mypy 会抱怨这个。是否有另一种方法来键入提示此类实例级函数?

这在 mypy 中目前已损坏,因为它假定您正在创建一个方法,这是相关问题 https://github.com/python/mypy/issues/708

在 init 中键入函数工作正常,因为它不会认为它是 class 上的方法,以下代码正确通过类型检查并且 func 的类型是从范围。如果参数不可行,也可以直接键入属性赋值。

from collections.abc import Callable

class Foo:
    def __init__(self, func: Callable[[], int]):
        self.func = func

reveal_type(Foo(lambda: 0).func)
###OUTPUT###
file.py:7: note: Revealed type is "def () -> builtins.int"

另一个可以在问题中找到并避免在 init 中分配的解决方法是使用回调 Protocol,如下所示:

from typing import Protocol

class FuncCallback(Protocol):
    def __call__(self, /) -> int:
        ...

class Foo:
    func: FuncCallback

    def __init__(self, func):
        self.func = func

这使得 func 成为一个 FuncCallback 协议,在调用时不需要任何参数,returns 成为一个 int 就像你的 Callable.