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

当我使用reveal_typeof 时mypy,关于result变量的输出是Any.

这个程序的输出是:

<Task finished coro=<b() done, defined at ____.py:7> result=[1, 2, 3]>

我应该如何正确记录此功能?

4

1 回答 1

4

通常你可以通过打印它的类型来获得一些变量的基本注释:

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因为Taskis (subclass of) Awaitable

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

我们的选择现在缩小到Task它的父类之一Awaitable(包括最极端的情况——Any它是任何类的父类,并且 mypy 已向您提出)。

add_done_callbackisFuture方法,根据文档将接收未来对象作为它的参数。它不会是任何类型的Awaitable(如协程),而只是Future或其中的一些子类,如Task.

在选择类型注释时,最抽象地了解函数可以接受什么作为参数(正常工作)以及最具体地了解它可以返回的内容是有意义的。因此FutureTask我更愿意在两者之间进行选择Future(假设您不会Task仅使用特定的 attrs)。按照这个逻辑,最终的答案是:

def some_callback(result: asyncio.Future):
    print(result)

这听起来有点复杂和耗时,但是一旦你有了一个想法,你就可以更快地选择注释。

于 2017-11-21T16:32:23.500 回答