【问题标题】:What mechanism makes Python lambdas work without await keyword?什么机制使 Python lambda 在没有 await 关键字的情况下工作?
【发布时间】:2019-11-11 23:01:19
【问题描述】:

我刚刚注意到一些令人惊讶的事情。考虑以下示例:

import asyncio

async def wait_n(n):
    asyncio.sleep(n)

async def main(fn):
    print("meh")
    await fn(1)
    print("foo")

loop = asyncio.get_event_loop()
loop.run_until_complete(main(wait_n))

当我们运行它时,我们理所当然地收到以下警告:

awaitable_lambda.py:5: RuntimeWarning: coroutine 'sleep' was never awaited

asyncio.sleep(n)

这是因为在 wait_n 中我们调用了 asyncio.sleep(n) 而没有 await

但现在考虑第二个例子:

import asyncio

async def main(fn):
    print("meh")
    await fn(1)
    print("foo")

loop = asyncio.get_event_loop()
loop.run_until_complete(main(lambda n: asyncio.sleep(n)))

这次我们使用lambda,令人惊讶的是,即使没有await,代码也能正常工作。

我知道我们不能在 Python lambda 表达式中使用 await,所以这似乎是一个改进人体工程学的功能,但它给我带来了一些问题:

  1. 这究竟是如何工作的?这个简单的在任何协程函数之前“注入”await 吗?
  2. 这是否记录在某处 (PEP)?
  3. 还有其他影响吗?我们可以安全地从 lambda 表达式调用协程函数并依靠 Python 为我们等待事情吗?

【问题讨论】:

  • 在第一个 sn-p 中将 async def wait_n(n): asyncio.sleep(n) 更改为 def wait_n(n): return asyncio.sleep(n) 并且您得到与 lambda 完全等价的内容,这表明 lambda 是 def 和隐式返回

标签: python lambda async-await python-asyncio


【解决方案1】:

任何异步函数都会返回一个awaitable。你不需要立即“await函数调用”,你只需要最终await返回的等待值。即,这两个是等价的:

await asyncio.sleep(1)
awaitable = asyncio.sleep(1)
await awaitable

因此,应该很容易看出 lambda 的调用 fn(1)(隐式)返回一个可等待对象,而 await 等待它。另一方面,async def wait_n 永远不会返回可等待的 sleep,也永远不会等待它本身。

作为一个推论示例,如果您有任何围绕 async 函数的包装器,则该包装器不一定需要是 async 本身:

def add_1(func):
    def wrapper(a):
        return func(a + 1)  # passes the awaitable return value through

    return wrapper

@add_1
async def foo(a):
    await asyncio.sleep(a)

async def main():
    await foo(1)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-06-04
    • 2013-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多