Python: Введите подсказку для «имеет метод»

#python #types #annotations #type-hinting #python-typing

Вопрос:

Например, у нас есть класс:

 class A:
    def send(msg: bytes) -> None:
        # implementation...
        pass
    
    def recv(n: int) -> bytes:
        # implementation
        pass
 

и функция:

 def a(obj, n: int) -> None:
    received = obj.recv(n)
    obj.send(received)
 

Довольно очевидно, что A в качестве аргумента могут быть переданы не только экземпляры класса obj , но и экземпляры socket.socket , возможно, других классов, которые имеют recv и send реализованы.

Как можно аннотировать/вводить obj аргумент подсказки, чтобы он говорил что-то вроде:

 obj type must possess methods send and recv
send method must be of type Callable[[bytes], None]
recv method must be of type Callable[[int], bytes]
 

Ответ №1:

Что вам точно нужно, так это типизация утки (структурный подтип) с помощью набора текста.Протокол. Некоторые примеры приведены в этом списке.

Классы протоколов определяются следующим образом:

 class Proto(Protocol):
    def meth(self) -> int:
        ...
 

Такие классы в основном используются для проверки статических типов, которые распознают структурные подтипы (статическая утиная типизация), например:

 class C:
    def meth(self) -> int:
        return 0

def func(x: Proto) -> int:
    return x.meth()

func(C())  # Passes static type check
 

Где встроенный пример

class typing.SupportsIndex

Азбука с одним абстрактным методом __index__ .

Так что для вашего случая это может быть что-то вроде:

 from typing import Protocol


class SupportsSendReceive(Protocol):
    def send(self, msg: bytes) -> None:
        ...
    
    def recv(self, n: int) -> bytes:
        ...


def a(obj: SupportsSendReceive, n: int) -> None:
    received = obj.recv(n)
    obj.send(received)
 
  • Обратите внимание, что многоточие ... не означает, что вы должны вставлять в него код. Это действительно так, как должно быть. Или вы также можете вставить pass туда, если вас беспокоят 3 точки 🙂