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

Posted

技术标签:

【中文标题】如何在 python 3.5 中使对象可等待?【英文标题】:How to make object awaitable in python 3.5? 【发布时间】:2017-05-31 12:01:47 【问题描述】:

我有一个伪异步生成器,它实际上在初始化时获取所有需要的数据。我想用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__ 方法并且看起来这个方法应该返回迭代器对象,但是我怎样才能为实际上不可迭代的对象创建迭代器?

【问题讨论】:

return = [MakeObject() for i in make_http_request()] 导致 SyntaxError 请提供所有代码 (minimal, complete and verifiable example)。 总是提出问题完整的错误信息。 我更新了问题,谢谢你的cmets。 如果你只需要发出http请求,请使用aiohttp 【参考方案1】:

__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')

【讨论】:

以上是关于如何在 python 3.5 中使对象可等待?的主要内容,如果未能解决你的问题,请参考以下文章

python - 如何在python中使没有簇质心的簇不可见?

如何在 Cloud Functions for Firebase 中使 HTTP 请求异步/等待?

如何使python等待对象

如何在 .net 中使类可序列化而无需 Serializable 属性

如何在控制器方法中使 JWT 令牌授权可选

如何在 Flutter 的 tabbarwiew 中使 webview 可滚动