异步生成器不是迭代器?

时间:2017-02-24 21:32:11

标签: python python-asyncio

在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) ...

尝试使用异步迭代器时,会出现'yield inside async'错误。 建议的解决方案是实现自己的生成器:

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'对象不是迭代器”

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

我错过了什么吗?

谢谢!

3 个答案:

答案 0 :(得分:9)

所以,正如@bosnjak所说,你可以使用async:

globalSearch

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

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

但我不建议这样做。

  

我认为如果你打算把它称为迭代器,因为它具有完全相同的接口,所以我可以编写异步迭代器并在依赖于next()调用的框架上使用

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

  1. Python协同程序内置于生成器之上
  2. 根据python的Zen,显式优于隐式。这样你就可以看到代码可以暂停的地方。
  3. 这就是为什么不能将it = async_iterator() await it.__anext__() iter与异步迭代器一起使用的原因。并且您不能将它们用于需要同步迭代器的框架。因此,如果要使代码异步,则必须使用异步框架。 Here很少。

    另外,我想谈谈迭代器和生成器。 Iterator是一个具有next__iter__方法的特殊对象。而generator是一个包含__next__表达式的特殊函数。 每个生成器都是迭代器,但反之亦然。异步迭代器和生成器也可以接受同样的事情。是的,因为python 3.6你可以编写异步生成器!

    yield

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

答案 1 :(得分:4)

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

async for TARGET in ITER:
    BLOCK
else:
    BLOCK2

根据PEP 492

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

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

另外,请检查Differences from generators

  

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

答案 2 :(得分:1)

我用它来通过列表进行异步循环

class AsyncRange(object):
    def __init__(self, length):
        self.length = length
        self.i = 0

    async def __aiter__(self):
        return self

    async def __anext__(self):
        index = self.i
        self.i += 1
        if self.i <= self.length:
            return index
        else:
            raise StopAsyncIteration

然后简单地说:

async for i in AsyncRange(my_list):
    # your code