我正在为一个框架开发一个可扩展的插件子系统,但我一直坚持如何让系统从插件本身动态和无缝地加载插件。我已经知道如何添加插件(可能会使用入口点)。举个例子:
插件.py
from framework.plug_lib import plugin
@plugin
def foo():
return 2
@plugin
def bar():
return foo()
插件.py
from framework.plug_lib import plugin
@plugin
def foo():
return 3
framework.plug_lib.py
loaded_plugins = {}
class Plugin(object):
def __init__(self, plug): #note plug could be class, function, method, etc
self.plug = plug
def plug_load(self):
loaded_plugins[self.plug.__name__] = self.plug
def plug_get_loaded_version(self):
try:
return loaded_plugins[self.plug.__name__]
except KeyError:
raise RuntimeError('No plugin %s loaded.' % self.plug.__name__)
def plugin(plug):
return Plugin(plug)
def load(plugin_path):
# get plugin by searching entry-points, other basic logic
plugin.plug_load()
使用示例:
from framework.plug_lib import load, loaded_plugins
load('pluga.foo')
load('pluga.bar')
loaded_plugins['bar']() # 2
.
from framework.plug_lib import load, loaded_plugins
load('plugb.foo')
load('pluga.bar')
loaded_plugins['bar']() # 3
这被简化以试图简明扼要地说明问题。在真实的框架中,有多种不同类型的插件,它们都有不同的loaded_plugin
类比。如果插件的容器是一个类,我可能会想办法将它硬塞到描述符或其他东西中,但其中的一部分目的是重构一些当前包装插件的样板代码。我可以自定义模块本身检查它自己的命名空间并检索它的成员的方式,插件模块本身没有或最多只有一个简单的行吗?我基本上需要__getattribute__
与模块本身等效的东西,这样我就可以Plugins
表现得像穷人的描述符,并self.plug_get_loaded_version()
在尝试访问它们以外的任何东西时返回plug_load()
方法,我想,但我不知道该怎么做。也许是包时代码(setup.py 中的东西),但我认为如果不每次都重新构建,您将无法在开发模式下处理已安装的包。有什么想法吗?