如何在等待的子类中使用super()?

时间:2018-10-02 09:37:27

标签: python python-asyncio

我想通过子类化将新功能添加到现有的等待类中。

让我们从一个非常简单的基类开始,创建一些对象,这些对象在短暂睡眠后异步返回99。子类应仅将+1添加到结果中。

我找不到使用super()来引用基类的正确方法。

import asyncio

class R99:
    def __await__(self):
        loop = asyncio.get_event_loop()
        fut = loop.create_future()
        loop.call_later(0.5, fut.set_result, 99)
        return fut.__await__()

class R100(R99):
    async def add1(self):
        v = await R99()
        #v = await super().__await__()   # <== error
        return v + 1

    def __await__(self):
        return self.add1().__await__()

async def test():
    print(await R99())
    print(await R100())

asyncio.get_event_loop().run_until_complete(test())

2 个答案:

答案 0 :(得分:4)

await method必须返回一个迭代器,因此您可以使其成为生成器并使用yield from语法:

class R100(R99):

    def __await__(self):
        v = yield from super().__await__()
        return v + 1

答案 1 :(得分:2)

如果允许您修改R99,则可以使__await__()调用实际的协程,该协程可以按常规方式链接到super()

import asyncio

class R99:
    async def await_coro(self):
        loop = asyncio.get_event_loop()
        fut = loop.create_future()
        loop.call_later(0.5, fut.set_result, 99)
        return await fut

    def __await__(self):
        return self.await_coro().__await__()

class R100(R99):
    async def await_coro(self):
        v = await super().await_coro()
        return v + 1

如果这不是一个选择,@ Vincent的回答恰好说明了如何从一个__await__链接到另一个。请注意,您以为await是新的yield from是正确的-实际上,通常没有理由在新编写的异步代码中使用yield from。 (这当然不适用于委托给子生成器的与异步无关的生成器;欢迎继续使用yield from。)

但是,通过实现__await__(),您将进入使用生成器实现协程的较低级API。在此级别,yield暂停协程,将控制返回到事件循环,yield from委托给另一个实现协程的生成器。在新代码中,该层的唯一有效目的是在不使用解释器的情况下实现等待对象。在Python / C或Cython中。通过提供一个返回迭代器的__await__来完成此操作,如图here所示。结果对象等效于async def