什么机制让 Python lambdas 在没有 await 关键字的情况下工作?
回答问题 我刚刚注意到一些令人惊讶的事情。考虑以下示例: 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
回答问题
我刚刚注意到一些令人惊讶的事情。考虑以下示例:
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
,代码也能正常工作。
我知道我们不能在 Pythonlambda
表达式中使用await
,所以这似乎是一个改善人体工程学的功能,但它给我带来了一些问题:
-
这究竟是如何工作的?这个简单的在任何协程函数之前“注入”一个
await
吗? -
这是否记录在某处(PEP)?
-
这还有其他影响吗?我们可以安全地从 lambda 表达式调用协程函数并依靠 Python 为我们等待事情吗?
Answers
任何异步函数都会返回一个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)
更多推荐
所有评论(0)