如何向asyncio.Task添加类型注释

8

我有一段代码长这样:

import asyncio
from typing import List

def some_callback(result):
    print(result)

async def b() -> List[int]:
    return [1, 2, 3]

async def a() -> None:
    search = asyncio.ensure_future(b())
    search.add_done_callback( some_callback)
    await search

loop = asyncio.get_event_loop()
loop.run_until_complete(a())
loop.close()

我正在尝试为函数some_callback添加类型注释,但我无法完全理解如何注释变量result。它应该是Coroutine吗?或者可能是Awaitable
当我使用mypyreveal_type时,关于变量result的输出是Any
此程序的输出是:
<Task finished coro=<b() done, defined at ____.py:7> result=[1, 2, 3]>

我应该如何正确地记录这个函数?
1个回答

6
通常,您可以通过打印其类型来获取某些变量的基本注释:

def some_callback(result):
    print(type(result))

虽然它会显示一些内部的<class '_asyncio.Task'>类型,但看起来我们可以将其视为常规的asyncio.Task

def some_callback(result):
    print(type(result) is asyncio.Task)  # True

但正如你所指出的,我们也可以使用更抽象的类型而不仅仅是Task,比如Awaitable,因为TaskAwaitable的子类:

print(issubclass(asyncio.Task, typing.Awaitable))  # True

我们现在的选择已经缩小到Task或其父类之一,例如Awaitable(包括最极端情况-Any,它是任何类的父类,而mypy也向您提供了此选项)。 add_done_callbackFuture方法,根据文档,它将接收future对象作为其参数。它不会是任何类型的Awaitable(如协程),而只能是Future或其某些子类,如Task
当选择类型注释时,最好对函数可以接受的参数进行最抽象描述(正常工作),并对其可以返回的结果进行最具体描述。因此,在选择FutureTask之间,我更喜欢Future(假设您不打算使用Task特定属性)。根据这种逻辑,最终答案是:
def some_callback(result: asyncio.Future):
    print(result)

这听起来有点复杂和耗时,但一旦你有了概念,就能更快地选择注释。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接