简体   繁体   English

带有生成器表达式的 asyncio.gather

[英]asyncio.gather with generator expression

Why doesn't asyncio.gather work with a 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())

The second variant gives:第二种变体给出:

[...]
  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>

Is this expected behavior?这是预期的行为吗?

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

This doesn't work because this is passing the generator object as argument to gather .这不起作用,因为这将生成器 object作为参数传递给gather gather doesn't expect an iterable , it expects coroutines as individual arguments. gather不期望一个可迭代的,它期望协程作为单独的 arguments。 Which means you need to unpack the generator.这意味着您需要打开生成器的包装。

Unpack the generator:打开生成器的包装:

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

We must expand it because asyncio.gather expects a list of arguments (ie asyncio.gather(coroutine0, coroutine1, coroutine2, coroutine3) ), not an iterable我们必须扩展它,因为asyncio.gather需要一个 arguments 列表(即asyncio.gather(coroutine0, coroutine1, coroutine2, coroutine3) ),而不是一个可迭代的

Python uses * / ** for both 'un-packing' and just 'packing' based on whether it's used for variable assignment or not. Python 使用* / **用于“解包”和“打包”,具体取决于它是否用于变量赋值。

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

In this case, all non-keyworded args are getting put into a tuple args and all kwargs are getting packed into a new dictionary.在这种情况下,所有非关键字 args 都被放入一个元组args中,所有 kwargs 都被打包到一个新字典中。 A single variable passed in still gets packed into a tuple( * ) or dict( ** ).传入的单个变量仍被打包到元组( * )或字典( ** )中。

This is kind of a hybrid这是一种混合

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

But here it unpacks:但在这里它解包:

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

So basically if it's on the left side of the equals or if it's used in a function/method definition like *foo it's packing stuff into a list or tuple (respectively).所以基本上,如果它位于等号的左侧,或者如果它用于像*foo这样的函数/方法定义中,它会将内容打包到列表或元组中(分别)。 In comprehensions, however, it has the unpacking behavior.然而,在理解中,它具有解包行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM