我想写一个简单的插件系统。你知道吗
a)为此,我发现下面的代码使用了3.6魔术函数__init_subclass__
https://stackoverflow.com/a/41924331/1506569,它改编自pep487,在plugins
列表中注册父类定义中的每个类。你知道吗
b)我现在想“强制”插件的编写者实现一个特定的方法,该方法将由我的程序调用。理想情况下,这会在导入时警告用户,他的插件不会工作,但不会阻止程序运行。为此,我尝试将ABC作为父类添加到插件中,并添加@abstractmethod
。你知道吗
我最初尝试ABC和__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
列表中。
调用函数Render.do_something
(底部的循环)也不会引发异常。它什么也不做。你知道吗
我发现的一个解决方案是:https://stackoverflow.com/a/54545842/1506569,它只是比较基类和子类上的函数对象是否不同(通过使用class和cls)。不过,这使得从ABC继承变得不必要,而且似乎比需要的更复杂。你知道吗
第二次尝试,没有ABC:
class Plugin():
plugins = []
@classmethod
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
if getattr(cls, 'do_something') is getattr(__class__, 'do_something'):
print("Warning: Your plugin might not work, missing 'do_something'")
else:
__class__.plugins.append(cls())
def do_something(self):
...
class Render(Plugin):
def __init__(self):
print("Render init")
for plugin in Plugin.plugins:
plugin.do_something()
这个版本是可行的,但对我来说似乎很复杂,似乎它可能会进一步打破线?你知道吗
有没有我错过的方法?为什么实例化可以工作? 抱歉,如果我错过了一个类似的问题,我试图寻找了很长一段时间。你知道吗
如果您只想强制子类实现一个方法,
@abstractmethod
就足够了。你不需要init_subclass
。您的代码是正确的,但是,您没有在任何地方实例化Render
。在创建对象而不是类时,抽象方法会给您一个错误。如果你写Render()
,你会得到一个错误相关问题 更多 >
编程相关推荐