我正在为一个框架开发一个可扩展的插件子系统,但我仍然坚持如何让系统从插件本身动态无缝地加载插件。我已经知道如何添加插件(可能会使用入口点)。举个例子:
pluga.py
from framework.plug_lib import plugin
@plugin
def foo():
return 2
@plugin
def bar():
return foo()
plugb.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
表现得像穷人的描述符,并且每当尝试访问除{{1}之外的任何内容时都返回self.plug_get_loaded_version()
我认为,方法,但我不知道如何做到这一点。也许打包时间代码(在setup.py中的东西),但我认为你不能在开发模式下处理已安装的软件包,而不是每次都重建。那里有什么想法吗?