我正在尝试编写一个简单的插件系统。
a)为此,我使用了3.6魔术函数__init_subclass__
https://stackoverflow.com/a/41924331/1506569找到了以下代码,该函数改编自PEP 487,该函数将定义中的每个类都注册在{{1}中的父类中}列表。
b)现在,我想“强制”插件的编写者实现一种特定的方法,该方法将由我的程序调用。理想情况下,这将在导入时警告用户,他的插件将不起作用,但不会阻止程序运行。为此,我尝试将ABC作为父类添加到插件,并添加plugins
。
我最初尝试使用ABC和@abstractmethod
:
__init_subclass__
这里的问题是,实例化from abc import ABC, abstractmethod
class Plugin(ABC):
plugins = []
@classmethod
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
try:
__class__.plugins.append(cls()) # Does not raise exception
except Exception as e:
print("Warning: Your plugin might not work, missing abstract method")
@abstractmethod
def do_something(self):
...
class Render(Plugin):
def __init__(self):
print("Render init")
# does not implement 'do_something'
for plugin in Plugin.plugins:
plugin.do_something() # Calls 'do_something' on Render, without raising an exception
不会引发异常,而是将实例化的__class__.plugins.append(cls())
对象添加到Render
列表中。
调用函数plugins
(底部的循环)也不会引发异常。它什么都不做。
我在这里找到了一个解决方案:https://stackoverflow.com/a/54545842/1506569,它只是比较基类和子类上的函数对象是否不同(通过使用 class 和cls)。但这使得从ABC继承成为不必要,并且看起来比需要的更为复杂。
没有ABC的第二次尝试:
Render.do_something
此版本有效,但对我来说却令人困惑,看起来它可能会进一步中断?
我错过了一种方法吗?为什么实例化起作用? 抱歉,如果我错过了类似的问题,我尝试搜索了很长时间。
答案 0 :(得分:0)
如果只想强制子类实现方法,那么@abstractmethod
就足够了。您不需要init_subclass
。您的代码是正确的,但是您尚未实例化 Render
。当创建 objects 而不是类时,抽象方法将给您一个错误。如果您写Render()
,实际上会得到一个错误
无法使用抽象方法do_something实例化抽象类Render