asyncio.gather with generator expression



为什么 asyncio.gather 不能与生成器表达式一起使用?

import asyncio
async def func():
await asyncio.sleep(2)
# Works
async def call3():
x = (func() for x in range(3))
await asyncio.gather(*x)
# Doesn't work
async def call3():
await asyncio.gather(func() for x in range(3))
# Works
async def call3():
await asyncio.gather(*[func() for x in range(3)])
asyncio.run(call3())

第二个变体给出:

[...]
File "test.py", line 13, in <genexpr>
await asyncio.gather(func() for x in range(3))
RuntimeError: Task got bad yield: <coroutine object func at 0x10421dc20>

这是预期行为吗?

await asyncio.gather(func() for x in range(3))

这不起作用,因为这会将生成器对象作为参数传递给gathergather不期望可迭代对象,而是期望协程作为单独的参数。这意味着您需要打开发电机的包装。

打开生成器的包装:

await asyncio.gather(*(func() for i in range(10)))  # star expands generator

我们必须扩展它,因为asyncio.gather期望一个参数列表(即asyncio.gather(coroutine0, coroutine1, coroutine2, coroutine3)(,不是可迭代的

Python 使用*/**进行"解包"和"打包",具体取决于它是否用于变量赋值。

def foo(*args,**kwargs):...

在这种情况下,所有非关键字参数都被放入元组args,所有 kwarg 都被打包到新字典中。传入的单个变量仍然被打包到元组(*(或dict(**(中。

这是一种混合体

first,*i_take_the_rest,last = range(10)
>>> first=0,i_take_the_rest=[1,2,3,4,5,6,7,8],last=9
*a,b = range(1)
>>> a=[],b=0

但在这里它解开了:

combined_iterables = [*range(10),*range(3)]
merged_dict = {**first_dict,**second_dict}

所以基本上,如果它在等于的左侧,或者如果它用于函数/方法定义,比如*foo它分别将内容打包到列表或元组中。 然而,在理解中,它具有解包行为。

最新更新