Как заставить Mypy распознавать членство в протоколе класса в Callable? - PullRequest
0 голосов
/ 24 апреля 2020

Mypy правильно распознает приверженность класса протоколу, когда протокол используется в качестве простого параметра для функции с аннотацией типа. Однако, когда у меня есть функция, требующая использования вызываемого параметра, использующего этот протокол, Mypy пропускает членство в протоколе класса пользователя.

Неправильно ли я использую шаблон протокола Mypy, или в данный момент Mypy просто не поддерживает это?

(я видел, что у Mypy возникли проблемы с 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]"



1 Ответ

0 голосов
/ 24 апреля 2020

Если заменить определение call_foo на:

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

Ошибка исчезает, и программа продолжает работать ... Ситуация такая же, если прекратить использование протокола и сделать C a ребенок П.

Второй обходной путь:

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)
...