我正在使用David Beazley(在http://www.dabeaz.com/coroutines/(在{{3}}的精彩的三元组演示文稿中所描述的)作为协程生成器,我不知道如何键入装饰器consumer
。这是我到目前为止的内容:
from typing import Any, Callable, Generator, Iterable
ArbGenerator = Generator[Any, Any, Any]
def consumer(fn: ❓) -> ❓:
@wraps(fn)
def start(*args: Any) -> ArbGenerator:
c = fn(*args)
c.send(None)
return c
return start
使用示例,缩写为
@consumer
def identity(target: ArbGenerator) -> ArbGenerator:
while True:
item = yield
target.send(item)
@consumer
def logeach(label: Any, target: ArbGenerator) -> ArbGenerator:
while True:
item = yield
print(label, item)
target.send(item)
pipeline = identity(logeach("EXAMPLE", some_coroutine_sink()))
粗体❓
标记了我不确定的地方-我也不确定我定义的类型ArbGenerator
。 (问题是,在没有键入装饰器函数consumer
本身的情况下,我不确定mypy
是否正在使用该装饰器分析任何生成器函数,因此这就是为什么我不确定ArbGenerator
的原因。 )
我对最紧密的类型感兴趣,它比Any
更好,因此当我编写这些协程的链时,mypy
如果链条设置不正确,将会给我很好的警告。
(如果需要,请使用Python 3.5。)
答案 0 :(得分:1)
作为一种更具体的方法,您可以执行以下操作:
使用Callable
类型而不是问号。
将typing.Coroutine
用于targets
,并放下ArbGenerator
。
协程返回一个生成器,返回类型可以是Generator
或它的超类型之一
您应该使用可调用而不是问号的原因是fn
首先应该是可调用对象,这就是为什么用装饰器将其包装的原因。 Coroutine
将在调用对象后创建,并且返回类型显然也应该是可调用对象。
from typing import Any, Callable,Generator, Coroutine
from functools import wraps
def consumer(fn: Callable) -> Callable:
@wraps(fn)
def start(*args: Any) -> Coroutine:
c = fn(*args) # type: Coroutine
c.send(None)
return c
return start
@consumer
def identity(target: Coroutine) -> Generator:
while True:
item = yield
target.send(item)
@consumer
def logeach(label: Any, target: Coroutine) -> Generator:
while True:
item = yield
print(label, item)
target.send(item)
注意:正如文档中也提到的那样,如果要使用更精确的语法来注释生成器类型,则可以使用以下语法:
Generator[YieldType, SendType, ReturnType]
了解更多:https://docs.python.org/3/library/typing.html#typing.Generator