为什么在mypy中使用await表达式会得到无效的语法?

Wil*_*ner 5 python python-asyncio mypy

# file test.py
import asyncio
from inspect import iscoroutine
from typing import Any


async def a():
    print('run a')
    asyncio.sleep(1)
    return 1


async def b():
    # type: () -> Any
    print('run b')
    return a()


async def g():
    # type: () -> Any
    print('run g')
    s = b()
    while iscoroutine(s):
        print('in g', s)
        s = await s
    return s


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    a = loop.run_until_complete(g())
    print('finish ', a)
Run Code Online (Sandbox Code Playgroud)

当使用python3.6.6运行以上代码时,我得到:

run g
in g <coroutine object b at 0x10a980938>
run b
in g <coroutine object a at 0x10a95d620>
run a
finish  1

Process finished with exit code 0
Run Code Online (Sandbox Code Playgroud)

看来一切都很好。但是跑步的时候mypy test.py我得到了test.py:24: error: invalid syntax。这是什么意思?我的代码有问题吗?我的python解释器版本是3.6.6,mypy版本是0.620。

Mic*_*x2a 2

呵呵,这真是太奇怪了!

typed_ast我认为这是mypy 用于将 Python 源代码转换为抽象语法树的库中的一个错误。

我能够将您的问题简化为以下内容:

import asyncio

async def g():
    # type: () -> None
    await asyncio.sleep(1)
Run Code Online (Sandbox Code Playgroud)

这也会在包含“await”的行上出现语法错误。

但是,如果您执行以下操作,错误消息就会消失:

import asyncio

async def g() -> None:
    await asyncio.sleep(1)
Run Code Online (Sandbox Code Playgroud)

同样的解决方法(使用类型提示语法而不是注释语法也可以修复原始程序的问题)。似乎由于某种原因,基于注释的类型签名语法和“await”关键字不能很好地交互。

我怀疑这个问题之所以没有早点被发现,是因为大多数使用 async/await 的人也在使用 Python 3 的内置注释语法——当你想要与 Python 2 兼容时,通常会使用类型注释语法,但是async/await 仅限于 Python 3...

无论如何,我建议在 mypy 或 typed_ast 的问题跟踪器上提交问题——mypy 团队监控并维护这两个存储库。(或者,如果你愿意并且有一些空闲时间,甚至可以尝试typed_ast自己解决这个问题?对我来说,这感觉更像是一个疏忽,而不是一个根本上棘手的错误。)