我无法将头埋在暗示
Coroutine
的类型上。据我了解,当我们像这样声明一个函数时:
async def some_function(arg1: int, arg2: str) -> list:
...
我们有效地声明一个函数,它返回一个协程,当等待时,它返回一个列表。所以,输入提示的方法是:
f: Callable[[int, str], Coroutine[???]] = some_function
但是
Coroutine
泛型类型有3个参数!如果我们转到typing.py
文件,我们就可以看到它:
...
Coroutine = _alias(collections.abc.Coroutine, 3)
...
还有
Awaitable
类型,逻辑上 应该是 Coroutine
的父级,只有一个泛型参数(我想是返回类型):
...
Awaitable = _alias(collections.abc.Awaitable, 1)
...
所以也许以这种方式输入提示函数或多或少是正确的:
f: Callable[[int, str], Awaitable[list]] = some_function
或者是吗?
所以,基本上,问题是:
Awaitable
函数的情况下,可以使用 Coroutine
代替 async def
吗?Coroutine
泛型类型的正确参数是什么?它的用例是什么?正如文档所述:
Coroutine
ABC 的对象和实例都是Coroutine
ABC 的实例。Awaitable
对于
Coroutine
类型:
的通用版本。类型变量的方差和顺序对应于collections.abc.Coroutine
。Generator
Generator
又带有签名 Generator[YieldType, SendType, ReturnType]
。因此,如果您想保留该类型信息,请使用 Coroutine
,否则 Awaitable
就足够了。
Coroutine
类型采用与Generator
类型相同的签名:
Generator[YieldType, SendType, ReturnType]
由于对协程的未等待调用的结果是可等待的(它可以在
await
表达式中使用),因此可以使用以下类型提示:
Awaitable[ReturnType]
示例:
async def some_function(arg1: int, arg2: str) -> List[str]:
return ['foo']
coro: Awaitable[List[str]] = some_function(1, 'bar')
result = await coro
print(result)
# prints ['foo']
但是,对于暗示协程的类型,我认为它们本身都没有用处。 相反,我选择与您在上一个示例中所述类似的内容:
def return_coro() -> Callable[[int, str], Awaitable[List[str]]]:
async def some_function(arg1: int, arg2: str) -> List[str]:
return ['foo']
return some_function
注意,如果您尝试将其传递给明确需要协程的函数(例如 asyncio.run()),mypy 会感到不安。
协程函数对应的类型
async def some_function(arg1: A, arg2: B, /) -> R: ...
是
Callable[[A, B], Coroutine[Any, Any, R]]
。 返回类型是Coroutine
的第三个参数;其他参数是所使用的 async
框架的实现细节,因此 Any
适合可移植性和兼容性。typing.reveal_type(some_function)
和类型检查器来简单地检查。例如,MyPy 显示(使用其 Callable
简写符号):
Revealed type is "def [A, B, R] (A`-1, B`-2) -> typing.Coroutine[Any, Any, R`-3]"
如果需要完整的参数规范、文档,或者只是不需要依赖
Coroutine
,则可以使用带有 Protocol
的
async def __call__
来代替:
class SomeFunctionType(Protocol):
async def __call__(self, arg1: A, arg2: B, /) -> R: ...
虽然通常可以使用
Awaitable[R]
而不是 Coroutine[Any, Any, R]
,但在显式描述协程函数时应避免这样做:Awaitable[R]
仅表示 Coroutine[Any, Any, R]
与 所有其他可等待项共享的 有限功能集。各种重要的
async
框架功能,例如 asyncio.run
或 asyncio.create_task
,依赖于完整的功能集,因此仅适用于实际的 Coroutine
。