Python 如何使用类型暗示在生成器上注释装饰器?
正如David Beazley(at)在优秀的三连载演示文稿中所描述的那样,我将生成器作为协同程序来使用,我不知道如何键入装饰者Python 如何使用类型暗示在生成器上注释装饰器?,python,python-3.x,generator,type-hinting,Python,Python 3.x,Generator,Type Hinting,正如David Beazley(at)在优秀的三连载演示文稿中所描述的那样,我将生成器作为协同程序来使用,我不知道如何键入装饰者消费者。以下是我目前掌握的情况: from typing import Any, Callable, Generator, Iterable ArbGenerator = Generator[Any, Any, Any] def consumer(fn: ❓) -> ❓: @wraps(fn) def start(*args: Any) -&g
消费者。以下是我目前掌握的情况:
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
。(问题是,如果没有键入(decorator)函数consumer
本身,我不确定mypy
是否正在使用该decorator分析任何生成器函数,因此我不确定ArbGenerator
)
我对最紧的类型感兴趣,它比任何
都好,因此当我构建这些协同程序的链时mypy
会在链设置不正确时给我很好的警告
(Python 3.5,如果有必要的话。)作为一种更具体的方式,您可以做以下几件事:
使用Callable
类型而不是问号
对目标使用键入.Coroutine
,然后放下生成器
协同程序返回一个生成器,返回类型可以是生成器
或其超类型之一
您应该使用callable而不是问号的原因是fn
一开始应该是一个可调用的对象,这就是为什么要用decorator来包装它。调用对象后将创建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]
阅读更多信息:我倾向于将显式类型视为可选类型,这似乎是Python社区中最慷慨的类型应用。在这种情况下,对于(未来的)程序员来说,任何类型的输入都可能比单独的duck类型更痛苦,所以我会省略它。@AdamSmith-TBH我认为(省略显式类型)是Python的哲学-所以当我在新的工作(我对Python比较陌生)时,我有点惊讶这种类型的提示甚至存在,而且我的同事正在大量使用它。这对你来说是个好消息!我很想在这里看到一个好的解决方案,因为强显式类型和协同程序对我来说都是弱点,我屏住呼吸看着这个问题:)@davidbak为什么不使用typing.Coroutine
?@Kasr-mvd-谢谢。出于某种原因,我认为Coroutine
特定于异步。出于某种原因,我认为Coroutine
特定于异步。现在,我一直在运行mypy--strict
,但是这个解决方案几乎可以与mypy--strict一起工作--允许任何泛型
具有非特定的可调用
和corroutine
和生成器
:我将其编辑为在消费者内部包装的start
中提示c
,需要避免在
return c`中出现错误,Any
不是一个Coroutine
。我想我想知道为什么来自Coroutine的返回类型不是Coroutine
,因为它们显然是(yield
在分配的RHS上)?@davidbak,因为它们不返回Coroutine
。事实上,它们返回None
(Python抽象表示没有任何对象)。但是,如果要使生成器的键入更精确,可以使用generator[YieldType,SendType,ReturnType]
语法。在这里阅读更多