为什么异步函数从外部作用域错误地绑定名称?[复制]

Why async function binds name incorrectly from the outer scope? [duplicate]

提问人:UpTheIrons 提问时间:12/27/2022 最后编辑:UpTheIrons 更新时间:5/11/2023 访问量:278

问:

这是一个通过迭代循环的异步函数生成器。我希望这个关闭会尊重外部范围的名称。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

Python 异步 命名空间 闭包 python-asyncio

评论

2赞 Abdul Niyas P M 12/27/2022
听起来像是后期绑定闭包的副本
0赞 Abdul Niyas P M 12/27/2022
要修复它,请将您的协程重写为async def coro(param=param)
1赞 Axe319 12/27/2022
这并不特定于协程。这只是与所有函数定义(和闭包)关联的默认 python 行为。
0赞 Michael Szczesny 12/27/2022
此代码不异步运行或使用 coro 作为闭包。

答:

1赞 Xiddoc 12/27/2022 #1

只有在函数运行后,它才会计算以下行:coro

print(param ** 2)

届时,它将检查其值并对其进行评估。那么它的价值是什么呢?paramparam

查看代码,我们可以看到该值是在迭代过程中设置的: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
请检查有问题的更新。 函数不应作为我的程序设计的参数。我还在函数中添加了异步代码。coroparamcoro
0赞 Axe319 12/27/2022
你的程序的设计是它不能按预期工作的具体原因。
0赞 Michael Szczesny 12/27/2022
我不明白您的更新,但我编辑了答案以使用具有所需参数绑定的异步闭包。
0赞 UpTheIrons 12/28/2022
@MichaelSzczesny 关闭更新解决了它。谢谢。