Python 如何要求抽象方法是协同程序?
如何要求抽象基类将特定方法实现为协同路由。例如,考虑ABC:Python 如何要求抽象方法是协同程序?,python,abstract-class,python-asyncio,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与ABC中的async不同,但这一操作成功。只有当func是async时,才能成功执行此操作。
import abc
class Foo(abc.ABC):
@abc.abstractmethod
async def func():
pass
现在,当我将其子类化并实例化时:
class Bar(Foo):
def func():
pass
b = Bar()
虽然
func
与ABC中的async
不同,但这一操作成功。只有当func
是async
时,才能成功执行此操作。您可以使用\uuuu new\uuu
并检查子类是否以及如何重写父类的CORO
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())
警告
- 子类也可以重写
以抑制此约束\uuuuu new\uuuu
- 不仅可以等待
。比如说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)
change
更不用说对象、其他原始未来、任务中的await o.change(key, value)
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
Bar
中再次定义async def func()
@abc.abstractmethod
不考虑func()
是否异步。是的,我理解。我想问的是,除了编写自定义的元类之外,是否还有一种方法可以实现这一点。在类内测试函数func()
是一种方法,但它不是您想要的!谢谢,这非常有用,包括解决方案和注意事项!我认为有必要补充一点,即不建议将*args
和**kwargs
传递到\uuuuuuuu新的\uuuuuuuu
而不是\uuuuu初始\uuuuuuu
。由于Python 3.3+很可能会抛出一个错误(如果您这样做的话)。AFAIR.\uuuuu new\uuuu
可以接受第一个类以外的参数(3.3+不会抛出任何错误),\uuuu new\uuuu
是一个与其他任何函数一样的函数,所以为什么不起作用呢。\uuuu init\uuuu
是对象的initlializer,而这里是使用类创建的方法——这是一种不同的方法。