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的对象,它是完全可以接受的.
我怎么能重写这个函数定义,以便我可以注释第二个参数?
PEP 544 https://www.python.org/dev/peps/pep-0544/提出了结构化子类型化(静态鸭子式输入)。如果/当它被接受时,您将不需要显式的子类化,您将能够简单地定义自己的协议,这些协议将被静态类型检查器理解。
正如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)