python 优雅地实现插件架构

mac2022-06-30  75

近日,决定用 python 实现插件架构,于是上 stackoverflow 逛了一下,在这里发现一段代码,非常喜欢。

提醒各位大侠注意,我对这段代码作了一点小小的改动:原 PLUGINS 是 list 对象,改动后 PLUGINS 是 dict 对象。

代码先贴出来,以飨观众:

''' 插件架构 ''' # 平台 class TextProcessor(object): PLUGINS = {} def process(self, text, plugins=()): if plugins is (): for plugin_name in self.PLUGINS.keys(): text = self.PLUGINS[plugin_name]().process(text) else: for plugin_name in plugins: text = self.PLUGINS[plugin_name]().process(text) return text @classmethod def plugin_register(cls, plugin_name): def wrapper(plugin): cls.PLUGINS.update({plugin_name:plugin}) return plugin return wrapper # 插件 @TextProcessor.plugin_register('plugin1') class CleanMarkdownBolds(object): def process(self, text): return text.replace('**', '') # 测试 processor = TextProcessor() print(processor.PLUGINS) # {’plugin1': <class '__main__.CleanMarkdownBolds'>} processed = processor.process(text="**foo bar**", plugins=('plugin1', )) processed = processor.process(text="**foo bar**")

这段代码运行良好!但是它是单文件,不适合实际使用。

在实际项目中,上面的三个注释下面的部分一定是拆开的,其中插件一般都约定俗成地放到 plugins 子目录下。

为了实现这个想法,走了很多弯路,花了两天时间!这期间查阅了__metaclass__原理, __subclass__()函数, package的组织方式等等。最后真的灵光一闪,成功实现!

项目结构:

├─ myproject ├─ run.py ├─ app ├─ __init__.py ├─ main.py ├─ platform.py ├─ plugins ├─ __init__.py ├─ plugin1.py ├─ plugin2.py

完整代码

# mpyproject/app/platform.py class TextProcessor(object): PLUGINS = {} def process(self, text, plugins=()): if plugins is (): for plugin_name in self.PLUGINS.keys(): text = self.PLUGINS[plugin_name]().process(text) else: for plugin_name in plugins: text = self.PLUGINS[plugin_name]().process(text) return text @classmethod def plugin_register(cls, plugin_name): def wrapper(plugin): cls.PLUGINS.update({plugin_name:plugin}) return plugin return wrapper # mpyproject/app/plugins/plugin1.py from ..platform import TextProcessor @TextProcessor.plugin_register('plugin1') class CleanMarkdownBolds(object): def process(self, text): return text.replace('**', '') # mpyproject/app/plugins/plugin2.py # 第二个插件! from ..platform import TextProcessor @TextProcessor.plugin_register('plugin2') class CleanMarkdownItalic(object): def process(self, text): return text.replace('--', '') # mpyproject/app/main.py from .platform import TextProcessor def test(): processor = TextProcessor() print(processor.PLUGINS) # {’plugin1': <class '__main__.CleanMarkdownBolds'>} processed = processor.process(text="**foo bar**", plugins=('plugin1', )) processed = processor.process(text="--foo bar--") # mpyproject/app/__init__.py from .plugins import * # mpyproject/app/plugins/__init__.py __all__ = ['plugin1', 'plugin2'] # mpyproject/run.py from app.main import test test()

说明:

优雅地实现插件架构,app/__init__.py 与 app/plugins/__init__.py 两个文件起了相互呼应的作用在 app 目录下,除了 app/__init__.py,不需要在别的任何地方显式地导入插件:from .plugins import * 或 from .plugins import plugin1若想添加插件 plugin3.py,可将其复制到 plugins 目录下,然后修改 app/plugins/__init__.py 文件为 __all__ = ['plugin1', 'plugin2', 'plugin3']插件是冷插拔的插件不是懒加载

优化方向

热插拔懒加载

转载于:https://www.cnblogs.com/hhh5460/p/6681363.html

相关资源:python中比较实用的经济类开发插件
最新回复(0)