为何可迭代数组中用[]包装元素、asyncio.gather中需使用*号?
问题1:为什么要用[]将main(i)包裹后追加到列表?
首先明确Python列表+=运算符的规则:列表做+=操作时,要求右侧必须是可迭代对象,会把右侧可迭代对象里的每一个元素挨个追加到原列表中。
这里的main是异步函数,直接调用main(i)不会立刻执行函数逻辑,只会返回一个协程对象,它本身不是可迭代对象。如果直接写tasks += main(i),代码会直接抛出TypeError: 'coroutine' object is not iterable的错误。
用[main(i)]就是把这个协程对象包装成一个单元素的列表,属于可迭代对象,就可以正常和tasks列表做相加操作了。
顺便提一句,这种写法和直接用tasks.append(main(i))效果完全一致,只是写法不同而已,实际开发中append的写法更常用。
问题2:调用asyncio.gather(*tasks)时的*号有什么作用?
这是Python的可迭代对象解包语法,作用是把列表里的每一个元素拆出来,作为独立的位置参数传给被调用的函数。
你可以看asyncio.gather的参数设计:它本身要求接收多个独立的协程对象作为位置参数,比如你要并发10个协程,原本要写asyncio.gather(main(0), main(1), main(2), ..., main(9))非常麻烦。
现在你把10个协程都存在了tasks列表里,如果直接传asyncio.gather(tasks),gather会把整个tasks列表当成一个参数处理,不会识别到列表里要执行的10个协程,自然没法实现预期的并发效果。加上*之后,就等价于把tasks里的10个协程挨个拆出来传给gather,刚好匹配它的参数要求。
举个简单的例子帮你理解:
def add(a, b, c): return a + b + c nums = [1,2,3] print(add(*nums)) # 等价于add(1,2,3),输出6
内容的提问来源于stack exchange,提问作者Joy Singh

