带生成器表达式的asyncio.gather

2024-09-28 01:31:50 发布

您现在位置:Python中文网/ 问答频道 /正文

为什么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>

这是预期的行为吗


Tags: inimportasyncioforasync表达式defrange
3条回答

Python使用*/**进行“取消打包”和“打包”,这取决于它是否用于变量赋值

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

在本例中,所有非关键字的arg都被放入一个tupleargs,所有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}

因此,基本上,如果它位于equals的左侧,或者如果它用于函数/方法定义中,比如*foo,那么它将把内容打包到列表或元组中(分别)。然而,在理解中,它具有解包行为

打开发电机的包装:

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

我们必须扩展它,因为^{}需要参数列表(即asyncio.gather(coroutine0, coroutine1, coroutine2, coroutine3)),而不是iterable

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

这不起作用,因为它将生成器对象作为参数传递给gathergather不需要iterable,它需要将协程作为单独的参数。这意味着你需要打开发电机的包装

相关问题 更多 >

    热门问题