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]
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.SupportsIndexAn 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)
... 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 :)If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With