Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Duck typing with python 3.5 style type-annotations

Supposing I have a function with a signature like:

def foo(self, name:str, stream):
    pass

I want to add an annotation to the "stream" argument so which means "you can have any object x as long as x.readline()->str.

So that means I could use any python file object as an argument here (since it has a readline method), but I could also provide an object which implements nothing but readline and it would be perfectly acceptable.

How could I rewrite this function definition so that I can annotate the 2nd argument?

like image 369
Salim Fadhley Avatar asked May 24 '17 10:05

Salim Fadhley


2 Answers

As ivanl notes, PEP 544 adds Protocols to support 'static duck typing'. This PEP was accepted recently and was added in Python 3.8. You can also try Protocols in Python 3.6 and 3.7 with Mypy using the typing-extensions package.

In your case, you would define a very simple Protocol SupportsReadline with a single method and use this in the annotation of your function arguments:

# Python 3.8+, for 3.6 & 3.7 replace 'typing' with 'typing_extensions'.
from typing import Protocol

class SupportsReadline(Protocol):
    def readline(self) -> str:
        ...

def func(name: str, stream: SupportsReadline) -> None:
    pass

Now any object with a readline method with a compatible signature is an implicit subtype of SupportsReadline and satisfies the annotation of your function argument. Note that LineRepeater does not inherit explicitly from SupportsReadline:

class LineRepeater:
    def readline(self) -> str:
        return "Hello again!"

func("a", LineRepeater())  # OK

The same holds for other objects if the method signature matches exactly:

from io import BytesIO, StringIO

func("a", StringIO())  # OK
func("a", open("foo.txt"))  # OK
func("a", BytesIO())  # ERROR (return type is bytes instead of str)
func("a", [])  # ERROR
func("a", 1)  # ERROR
func("a", object())  # ERROR
like image 116
schot Avatar answered Oct 17 '22 21:10

schot


Structural subtyping (static duck typing) is proposed by PEP 544 https://www.python.org/dev/peps/pep-0544/. If/when it is accepted you will not need an explicit subclassing, you will be able to simply define your own protocols that will be understood by static type checkers.

like image 28
ivanl Avatar answered Oct 17 '22 22:10

ivanl