python 优雅地实现插件架构

近日,决定用 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__.pyapp/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']
  • 插件是冷插拔的
  • 插件不是懒加载

优化方向

  • 热插拔
  • 懒加载
时间: 2024-10-30 08:38:00

python 优雅地实现插件架构的相关文章

插件架构学习体会(一) -- 宿主程序说:插件你得听我的

  看了一段时间的#develop,首先接触到的就是程序的插件架构.园子里也有许多不错的资料可以学习.随时把自己的认识写下来和大家交流,无疑会有很大帮助.闲话就不说了,进入正题.     说到插件架构,首先要有一个整体印象,到底什么才是插件架构?这个问题的答案很好找,找个插件架构的程序看看就可以了,比如VS,MyIE,再比如千千静听.我们可以开发不同功能的插件,加载到宿主程序上,功能就能发挥作用.宿主程序呢,完全不知道我们到底什么样的功能,怎么实现的.这里呢,我想从我们平常写程序时引用一些类库说

在C#程序中实现插件架构

程序|架构 原文作者:Shawn Patrick Walcheske 译者:电子科技大学 夏桅 [引言] 在.NET框架下的C#语言,和其他.NET语言一样提供了很多强大的特性和机制.其中一些是全新的,而有些则是从以前的语言和平台上照搬过来的.然而,这种巧妙的结合产生了一些有趣的方法可以用来解决我们的问题.这篇文章将讲述如何利用这些奇妙的特性,用插件(plug-ins)机制建立可扩展的解决方案.后面也将提供一个简要的例子,你甚至可以用这个东西来替换那些已经在很多系统中广泛使用的独立的程序.在一个

转:VIM python 自动补全插件:pydiction

1.这是一个相当不错的 Python 代码自动完成的脚本. 2. 3.可以实现下面python代码的自动补全: 4. 5.简单python关键词补全 6.python 函数补全带括号 7.python 模块补全 8.python 模块内函数,变量补全 9.from module import sub-module 补全 10.pydiction 插件安装 11. 12.pydiction 1.0 之后版本安装配置 13. 14.适用VIM7之后的版本. 15. 16.1.python_pydic

插件架构学习体会(二) -- 插件程序说:要求平等对话

在上一篇中我们知道,宿主程序对插件程序定义了一个规约,以此达到和插件程序通讯的目的.那插件有些不平衡,有时候我也需要知道你宿主程序的一些信息来完成我的工作,因此,我必须和你通讯,要有对话的权利.实际上,插件一般都会或多或少的用到宿主程序的上下文,比如vs插件,需要获取vs环境中的编辑的代码对象,才能完成它的工作比如格式化啊统计啊,再比如播放器的歌词插件,至少要获取播放器正在播放的是哪首歌吧.那么我们如何来实现这个通讯呢?我们知道宿主通过一个接口来操作插件,那么同理,插件可以通过一个接口来操作宿主

插件架构学习体会(三)--插件:兄弟们要团结

插件和宿主程序之间的相互通讯都不是什么问题了,那插件之间的相互通讯呢?理论上来说,插件之间的相互通讯是比较少见的,因为他们之间的通讯势必造成插件之间的依赖关系,那么对加载顺序也就有了严格的要求,我们应该尽量避免这种依赖.话说回来,如果需要插件间通讯,我们该如何做,不难想到,既然插件和宿主可以相互通讯,那我们只要让宿主做插件的中间人,就可以把两个插件联系在一起,毕竟宿主可以持有插件的引用.按照这个思路,继续修改程序:     首先我们得让宿主程序保存已加载插件的引用,并能获取制定的插件引用,修改一

《Python金融大数据分析》一第2章 基础架构和工具

第2章 基础架构和工具 Python金融大数据分析基础架构比体系结构还要重要得多. --Rem Koolhaas 你可能会说基础架构不是一切,但是没有基础架构,什么东西都可能毫无意义--在现实世界或者技术中都是如此.那么,我们所说的基础架构是指什么呢?理论上,它是使简单Python脚本或者更复杂的Python应用程序得以执行的硬件和软件组件. 但是,本章并不打算详细介绍硬件基础架构,因为所有Python代码和示例应该可以在几乎所有硬件上执行[1].我们在此也不打算讨论不同的操作系统,因为Pyth

以更优雅的方式实现弹性架构

为什么弹性架构是重要的         谈到IT系统架构,我们经常会用建筑架构来做类比,事实上,Architecture这个词也正是来自于传统的建筑行业.系统架构图就像建筑设计图一样,用来指导软件构建.同时,两者之间也存在一个巨大的不同,建筑物追求的是屹立千百年不变,而IT系统追求的是灵活性,以便随时应对真实世界的业务变化.从这个角度来看,IT系统更像一个有机的生命体,需要不停的改变自己去适应外界变化,才能让自身更有生命力.系统压力是一个重要的变化维度,是否能够随着系统压力的增减而动态的调整系统

使用python开发vim插件及心得分享_python

vim有各种强大的插件,这不仅归功于其提供的用来编写插件的脚本语言vimL,还得益于它良好的接口实现,从而支持python等语言编写插件.当vim编译时带有+python特性时就能使用python2.x编写插件,+python3则支持python3.x,可以使用vim --version来查看vim的编译特性. 要使用python接口,可以用:h python来查看vim提供的帮助文档,本文做一个简单的介绍.我们都知道在vim里可以执行bash命令,只需要:!command即可,那么vim里可以

Python资源大全

The Python Tutorial (Python 2.7.11) 的中文翻译版本.Python Tutorial 为初学 Python 必备官方教程,本教程适用于 Python 2.7.X 系列. 在线阅读 » Fork Me » The Python Tutorial (Python 3.5.1) 的中文翻译版本.Python Tutorial 为初学 Python 必备官方教程,本教程适用于 Python 3.5.x. 在线阅读 » Fork Me » Flask 是一个轻量级的 We