如何在python 3.5中使对象等待?

时间:2017-01-16 15:40:07

标签: python python-3.x python-3.5 python-asyncio

我有一个伪异步生成器,它实际上在初始化时获取所有需要的数据。我想用async for迭代它。我的简化代码如下所示:

class MyObject:
  def __init__(self, name):
     self.name

  def operate(self):
     pass

class MyGenerator:    
  def __init__(self, params):
    self.params = params
    self.current = 0
    self.last = None
    self.data = None

  async def make_http_request(self):
    await asyncio.sleep(1)
    return 42

  async def fetch_data(self):
    # actually it is not comprehentions since async comprehentions 
    # are not available in 3.5. It is a simple loop with await's
    return [MyObject(i) for i in self.make_http_request()]

  def __aiter__(self):
    self.data = await self.fetch_data()
    return self  

  def __anext__(self):
    try:
       result = self.data[self.current]
    except IndexError:
      raise StopAsyncIteration
    self.current += 1

    return result

如果我使用async for x in MyGenerator()运行此代码,我将获得"TypeError: 'async for' received an invalid object from __anext__: MyObject"

所以看起来异步生成器应该返回等待对象。所以问题是 - 我怎样才能使“经典”物体等待?看起来我应该实现__await__方法,看起来这个方法应该返回迭代器对象,但是如何为实际上不可迭代的对象创建迭代器呢?

1 个答案:

答案 0 :(得分:0)

__anext__ "Must return an awaitable"。目前它将返回MyObject()。我已经更改了下面的self.fetch_data() - 请查看此示例以演示异步运行的3个生成器:

import asyncio

import random


class MyGenerator:
    async def make_http_request(self):
        n = random.uniform(0.1, 3)
        await asyncio.sleep(n)
        return n

    def fetch_data(self):
        return [self.make_http_request() for i in range(5)]

    def __aiter__(self):
        self.current = 0
        self.data = self.fetch_data()
        return self

    def __anext__(self):
        # print("anext")
        try:
            task = self.data[self.current]
        except IndexError:
            raise StopAsyncIteration
        self.current += 1

        return task


async def main(tag):
    print(tag, "start")
    async for x in MyGenerator():
        print(tag, x)
    print(tag, "done")


loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.gather(main("A"), main("B"), main("C")))
loop.close()

print('done')