输入提示协程函数的正确方法?

问题描述 投票:0回答:3

我无法将头埋在暗示

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

或者是吗?

所以,基本上,问题是:

  1. 在类型提示
    Awaitable
    函数的情况下,可以使用
    Coroutine
    代替
    async def
    吗?
  2. Coroutine
    泛型类型的正确参数是什么?它的用例是什么?
python python-asyncio coroutine type-hinting
3个回答
14
投票

正如文档所述:

Coroutine
Coroutine
ABC 的对象和实例都是
Awaitable
ABC 的实例。

对于

Coroutine
类型:

collections.abc.Coroutine
的通用版本。类型变量的方差和顺序对应于
Generator

Generator
又带有签名
Generator[YieldType, SendType, ReturnType]
。因此,如果您想保留该类型信息,请使用
Coroutine
,否则
Awaitable
就足够了。


13
投票

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 会感到不安。


0
投票

协程函数对应的类型

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

© www.soinside.com 2019 - 2024. All rights reserved.