为什么 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))
这不起作用,因为这会将生成器对象作为参数传递给gather
。gather
不期望可迭代对象,而是期望协程作为单独的参数。这意味着您需要打开发电机的包装。
打开生成器的包装:
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
它分别将内容打包到列表或元组中。 然而,在理解中,它具有解包行为。