在异步生成器上使用next()

12

使用内置函数next(),可以逐步迭代生成器。例如:

def sync_gen(n):
    """Simple generator"""
    for i in range(n):
        yield i**2

sg = sync_gen(4)
print(next(sg)) # -> 0
print(next(sg)) # -> 1
print(next(sg)) # -> 4

在异步生成器上使用 next() 不起作用:

import asyncio

async def async_gen(n):
    for i in range(n):
        yield i**2

async def main():
    print("Async for:")
    async for v in async_gen(4):  # works as expected
        print(v)

    print("Async next:")
    ag = async_gen(4)
    v = await next(ag) # raises: TypeError: 'async_generator' object is not an iterator
    print(v)

asyncio.run(main())

是否存在类似v = await async_next(ag)这样的方式来获得与普通生成器相同的行为?


2
await iterator.__anext__() - Frank Yellin
3个回答

16

3
这就是我所期望的答案 :-) - Dietrich

8

如先前所述,next 在异步生成器上不起作用,因为它不是一个迭代器。

如果您必须使用函数,则可以创建一个帮助函数来代替使用 __anext__ 函数:

async def anext(ait):
    return await ait.__anext__()

ag = async_gen(4)
v = await anext(ag)
print(v)

编辑:

从Python 3.10版本开始,它们已经将此作为内置函数引入:anext


由于__anext__已经是可等待的,是否真的有必要将anext def async添加进去? - hl037_

4

PEP525 异步生成器对象描述了__anext__()方法:

agen.__anext__():返回一个可等待对象,当等待时执行一次异步生成器迭代。

因此可以这样调用它:

print("Async next:")
ag = async_gen(4)
v = await ag.__anext__()
print(v)

但是如此处讨论,这并不推荐


感谢您提供包括源代码在内的答案。虽然我不确定我理解链接stackoverflow答案中生成器和迭代器之间的推理。 - Dietrich

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接