2017-02-24 68 views
4

在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’对象不是一个迭代器”

我认为,如果你要调用的东西一个Iterator其原因它具有完全相同的接口,这样我就可以写异步迭代器和对在很大程度上依赖于未来的框架使用()调用。 如果你需要重写整个代码,以便能够使用异步的任何新的Python的能力是毫无意义的。

我错过了什么吗?

谢谢!

回答

2

所以,@bosnjak说,你可以使用异步为:

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

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

it = async_iterator() 
await it.__anext__() 

但我不建议这样做。

我认为,如果你要调用的东西一个Iterator它,因为它有完全一样的接口,这样我就可以写异步迭代器和对在很大程度上依赖于下一个()框架使用要求

不,实际上它是不一样的。常规同步迭代器和异步迭代器之间有区别。而对于有几个原因:

  1. Python的协同程序是建立在发电机内部顶部
  2. 据蟒蛇的禅,明确优于隐式。这样你就可以看到代码可以被暂停的地方。

这就是为什么它是不可能使用iternext异步迭代器。你不能将它们用于需要同步迭代器的框架。因此,如果您要使代码异步,则还必须使用异步框架。其中很少有Here

另外,我想谈谈迭代器和生成器的几句话。迭代器是具有__iter____next__方法的特殊对象。而发电机是一个包含yield表达式的特殊功能。 每个生成器都是一个迭代器,但不是反之亦然。异步迭代器和生成器可以接受同样的事情。是的,因为python 3.6你可以编写异步生成器!

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

您可以阅读PEP 525更多细节

+1

你说每个生成器都是一个迭代器,并且适用于异步生成器。为什么Python抱怨'async_generator'不是一个迭代器呢? – fenceop

+0

但是我怎么能'''.join([x x中的x异步])'而不是'''.join(x中的x异步xs)'?那只是'[]'对于async_generators有特殊的语法吗? –

+0

在python 3.6中添加了异步解析的新语法([PEP 530](https://www.python.org/dev/peps/pep-0530/))。所以你可以编写'[x x async for xs]''。而'(x for x in xs)' - 是生成器表达式(另一个括号可以在作为函数参数传递时简单省略)。我想你不能用异步代码创建生成器对象。所以'(x在xs中的x异步)'是无效的语法。 –

3

我相信新的语句中引入了异步发电机:

async for TARGET in ITER: 
    BLOCK 
else: 
    BLOCK2 

根据PEP 492

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

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

此外,检查Differences from generators

原住民协程对象不实行ITER下一个 方法。因此,它们不能被遍历或传递给ITER(), 列表(),元组()等内置插件。它们也不能用于..in循环中的 。企图用ITER下一个本地 协程对象将导致一个TypeError。

+0

所以,我必须假定有没有这样的事情asynchronic迭代器?只是不同步的发电机? – user1275011

+0

这就是我所知道的,但我不是专家,特别是不与异步。 – bosnjak

0

我通过列表中使用这异步循环

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