如何要求抽象方法是协程?

时间:2017-11-29 15:09:11

标签: python abstract-class python-asyncio

如何要求抽象基类实现特定方法作为协程。例如,考虑这个ABC:

import abc

class Foo(abc.ABC):
    @abc.abstractmethod
    async def func():
        pass

现在我将其子类化并实例化:

class Bar(Foo):
    def func():
        pass

b = Bar()

虽然func不是async,但仍然可以成功。如果funcasync

,我该怎么做才能成功

1 个答案:

答案 0 :(得分:3)

您可以使用__new__并检查子类是否以及如何覆盖父级的coros。

import asyncio
import abc
import inspect


class A:    

    def __new__(cls, *arg, **kwargs):
        # get all coros of A
        parent_coros = inspect.getmembers(A, predicate=inspect.iscoroutinefunction)

        # check if parent's coros are still coros in a child
        for coro in parent_coros:
            child_method = getattr(cls, coro[0])
            if not inspect.iscoroutinefunction(child_method):
                raise RuntimeError('The method %s must be a coroutine' % (child_method,))

        return super(A, cls).__new__(cls, *arg, **kwargs)

    @abc.abstractmethod
    async def my_func(self):
        pass


class B(A):

    async def my_func(self):
        await asyncio.sleep(1)
        print('bb')


class C(A):

    def my_func(self):
        print('cc')

async def main():
    b = B()
    await b.my_func()

    c = C()  # this will trigger the RuntimeError
    await c.my_func()


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

注意事项

  • 子类可以覆盖__new__以抑制此约束
  • 不仅可以等待async。例如

    async def _change_in_db(self, key, value):
        # some db logic
        pass
    
    def change(self, key, value):
        if self.is_validate(value):
            raise Exception('Value is not valid')
        return self._change_in_db(key, value)  
    

    可以像{/ 1>那样呼叫change

    await o.change(key, value)
    

    更不用说对象中的__await__,其他原始期货,任务......