提问人:UpTheIrons 提问时间:12/27/2022 最后编辑:UpTheIrons 更新时间:5/11/2023 访问量:278
为什么异步函数从外部作用域错误地绑定名称?[复制]
Why async function binds name incorrectly from the outer scope? [duplicate]
问:
这是一个通过迭代循环的异步函数生成器。我希望这个关闭会尊重外部范围的名称。for
import asyncio
coroutines = []
for param in (1, 3, 5, 7, 9):
async def coro():
print(param ** 2)
# await some_other_function()
coroutines.append(coro)
# The below code is not async, I made a poor mistake.
# Michael Szczesny's answer fixes this.
for coro in coroutines:
asyncio.run(coro())
虽然我期望结果在运行后,但这是实际输出:1, 9, 25, 49, 81
81
81
81
81
81
出乎意料的是,该名称每次都采用相同的值。param
您能解释一下为什么会发生这种情况,以及我如何实现在正确绑定名称的循环中创建大量异步函数的任务吗?for
答:
1赞
Xiddoc
12/27/2022
#1
只有在函数运行后,它才会计算以下行:coro
print(param ** 2)
届时,它将检查其值并对其进行评估。那么它的价值是什么呢?param
param
查看代码,我们可以看到该值是在迭代过程中设置的:param
for param in (1, 3, 5, 7, 9):
...
# For loop is over, param is now equal to 9
# since it was the last value it iterated on
然后,只有之后,函数才会运行:coro
for coro in coroutines:
asyncio.run(coro()) # 'param' is still set to 9, meaning that the output will always be 81
您可以改为向函数添加一个参数:coro
async def coro(coro_param):
print(coro_param ** 2)
...并在调用函数时将参数传递给函数:
for param in (1, 3, 5, 7, 9):
asyncio.run(coro(param))
评论
0赞
Xiddoc
12/27/2022
我不明白。那不是一堂课。
2赞
2 revsMichael Szczesny
#2
包含的代码不异步运行或使用 coro 作为闭包。函数在运行时以 计算。异步解决方案如下所示python
import asyncio
def create_task(param):
async def coro():
await asyncio.sleep(1) # make async execution noticeable
print(param ** 2)
return coro # return closure capturing param
async def main():
await asyncio.gather(*[create_task(param)() for param in (1,3,5,7,9)])
asyncio.run(main())
1 秒后输出
1
9
25
49
81
评论
0赞
UpTheIrons
12/27/2022
请检查有问题的更新。 函数不应作为我的程序设计的参数。我还在函数中添加了异步代码。coro
param
coro
0赞
Axe319
12/27/2022
你的程序的设计是它不能按预期工作的具体原因。
0赞
Michael Szczesny
12/27/2022
我不明白您的更新,但我编辑了答案以使用具有所需参数绑定的异步闭包。
0赞
UpTheIrons
12/28/2022
@MichaelSzczesny 关闭更新解决了它。谢谢。
评论
async def coro(param=param)