如何让 Mypy 在可调用对象中识别类的协议成员资格?


当协议被用作类型注释函数的简单参数时,Mypy正确地识别了类对协议的遵守。然而,当我有一个函数需要使用该协议的可调用参数时,Mypy会错过用户类的协议成员身份。

我是滥用了Mypy的协议模式,还是Mypy目前根本不支持这种模式?

(我看到过关于Mypy在Callables上遇到问题的帖子,这些Callables被分配给了一个类。所以这可能是一种已知的行为(

from typing_extensions import Protocol
from typing import Callable
class P(Protocol) :
def foo(self) -> None : ...

def requires_P(protocol_member : P) -> None : 
protocol_member.foo()
def requires_P_callable(protocol_member : P, function: Callable[[P],None]) -> None :
function(protocol_member)

class C :
def foo(self) :
print("bar")
if __name__ == '__main__' :
c = C()
def call_foo(c: C) -> None: 
c.foo()
requires_P(c) 
# mypy is fine with this
requires_P_callable(c, call_foo) 
# mypy complains : 
#       Argument 2 to "requires_P_callable" has incompatible type "Callable[[C], None]"; expected "Callable[[P], None]"

如果将call_foo的定义替换为:

def call_foo(c: P) -> None: c.foo()

错误消失,程序继续工作。。。如果停止使用Protocol并使C成为P.的子代,情况也是一样的

第二个解决方法是:

from typing import Callable, Protocol, TypeVar
_TP = TypeVar('_TP', bound='P')

class P(Protocol):
def foo(self) -> None:
...

class C:
def foo(self) -> None:
print("foo")

def requires_P_callable(prot: _TP, func: Callable[[_TP], None]) -> None:
func(prot)

def call_foo(c: C) -> None:
c.foo()

if __name__ == '__main__':
c = C()
requires_P_callable(c, call_foo)

最新更新