鸭子用python 3.5样式类型注释打字

Sal*_*ley 7 python type-hinting python-3.5 python-3.6

假设我有一个带有签名的函数:

def foo(self, name:str, stream):
    pass
Run Code Online (Sandbox Code Playgroud)

我想在"stream"参数中添加一个注释,这意味着"只要x.readline() - > str就可以拥有任何对象x.

所以这意味着我可以在这里使用任何python文件对象作为参数(因为它有一个readline方法),但我也可以提供一个只实现readline的对象,它是完全可以接受的.

我怎么能重写这个函数定义,以便我可以注释第二个参数?

iva*_*anl 8

PEP 544 https://www.python.org/dev/peps/pep-0544/提出了结构化子类型化(静态鸭子式输入)。如果/当它被接受时,您将不需要显式的子类化,您将能够简单地定义自己的协议,这些协议将被静态类型检查器理解。


sch*_*hot 5

正如ivanl所指出的,PEP 544添加了协议来支持“静态鸭子类型”。该PEP最近已被接受,并已添加到Python 3.8中。您还可以使用打字扩展包在Mypy中尝试使用Python 3.6和3.7中的协议。

对于您的情况,您将SupportsReadline使用一个方法定义一个非常简单的协议,并在函数参数的注释中使用它:

# 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
Run Code Online (Sandbox Code Playgroud)

现在,任何具有readline兼容签名方法的对象都是的隐式子类型,SupportsReadline并且满足函数参数的注释。请注意,LineRepeater它不会显式继承自SupportsReadline

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

func("a", LineRepeater())  # OK
Run Code Online (Sandbox Code Playgroud)

如果方法签名完全匹配,则其他对象也是如此:

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
Run Code Online (Sandbox Code Playgroud)