异步生成器不是迭代器?

新手上路,请多包涵

在 Python 中,您可以编写一个可迭代的生成器,例如:

 def generate(count):
    for x in range(count):
        yield x

# as an iterator you can apply the function next() to get the values.
it = generate(10)
r0 = next(it)
r1 = next(it) ...

尝试使用异步迭代器时,您会收到“异步内部收益”错误。建议的解决方案是实现您自己的生成器:

 class async_generator:
    def __aiter__(self):
        return self

    async def __anext__(self):
        await asyncio.sleep()
        return random.randint(0, 10)

# But when you try to get the next element
it = async_generator(10)
r0 = next(it)

你得到错误 "async_generator" object is not an iterator

我认为,如果您要将某些东西称为迭代器,那是因为它具有完全相同的接口,所以我可以只编写异步迭代器并在严重依赖 next() 调用的框架上使用。如果您需要重写整个代码才能使用异步,那么任何新的 Python 功能都是毫无意义的。

我错过了什么吗?

谢谢!

原文由 user1275011 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.1k
2 个回答

因此,正如@bosnjak 所说,您可以将异步用于:

 async for ITEM in A_ITER:
    BLOCK1
else: # optional
    BLOCK2

但是如果你想手动迭代,你可以简单地写:

 it = async_iterator()
await it.__anext__()

但我不建议这样做。

我认为,如果你要将某个东西称为迭代器,因为它具有完全相同的接口,所以我可以只编写异步迭代器并在严重依赖 next() 调用的框架上使用

不,实际上是不一样的。常规同步迭代器和异步迭代器之间存在差异。原因很少:

  1. Python 协程在内部构建于生成器之上
  2. 按照python之禅,显式优于隐式。这样您就可以真正看到代码可以暂停的地方。

这就是为什么不可能将 iternext 与异步迭代器一起使用。而且您不能将它们与需要同步迭代器的框架一起使用。所以如果你想让你的代码异步,你也必须使用异步框架。 这里 有一些。

另外,我想谈谈迭代器和生成器。迭代器是一个特殊的对象,具有 __iter____next__ 方法。而生成器是一个包含 yield 表达式的特殊函数。 每个生成器都是一个迭代器,但反之则不然。异步迭代器和生成器也可以接受同样的事情。是的,从 python 3.6 开始你就可以编写异步生成器了!

 async def ticker(delay, to):
    for i in range(to):
        yield i
        await asyncio.sleep(delay)

您可以阅读 PEP 525 了解更多详情

原文由 Michael Ihnatenko 发布,翻译遵循 CC BY-SA 3.0 许可协议

我相信为异步生成器引入了一个新声明:

 async for TARGET in ITER:
    BLOCK
else:
    BLOCK2

根据 PEP 492

基本上,这意味着你应该这样做:

 async for number in generate(10):
        print(number)

另外,检查 与生成器的差异

本机协程对象不实现 iternext 方法。因此,它们不能被迭代或传递给 iter() 、 list() 、 tuple() 和其他内置函数。它们也不能在 for..in 循环中使用。尝试在本机协程对象上使用 iternext 将导致 TypeError 。

原文由 bosnjak 发布,翻译遵循 CC BY-SA 3.0 许可协议

推荐问题