Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Type Hint for "has method"

For example, we have a class:

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

and a function:

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

It's fairly obvious, that not only instances of class A can be passed as the obj argument, but also instances of socket.socket, maybe other classes, which have recv and send implemented.

How can one annotate/type hint obj argument, so that it says something like:

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]
like image 560
winwin Avatar asked May 24 '26 15:05

winwin


1 Answers

What you exactly need is duck-typing (structural subtyping) via typing.Protocol. Some examples are in this list.

Protocol classes are defined like this:

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

Such classes are primarily used with static type checkers that recognize structural subtyping (static duck-typing), for example:

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

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

func(C())  # Passes static type check

Where a builtin example is

class typing.SupportsIndex

An ABC with one abstract method __index__.

So for your case, it could be something like:

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)
  • Note that the ellipsis ... doesn't mean you have to substitute code into it. It is really how it should be. Or you could also put pass in there if the 3 dots are bothering :)
like image 95
Niel Godfrey Ponciano Avatar answered May 26 '26 13:05

Niel Godfrey Ponciano



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!