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

优化方向

  • 热插拔
  • 懒加载

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

  1. [1] 插件架构(PLUG-IN)

    网上的一种比较好对插件的定义是:插件(Plug-in,又称addin.add-in.addon或add-on,又译外挂)也称为扩展,是一种遵循一定规范的应用程序接口编写出来的程序,主要是用来扩展软件功 ...

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

    阅读提示:这篇文章将讲述如何利用C#奇妙的特性,实现插件架构,用插件(plug-ins)机制建立可扩展的解决方案. 在.NET框架下的C#语言,和其他.NET语言一样提供了很多强大的特性和机制.其中一 ...

  3. 【Chromium中文文档】插件架构

    插件架构 转载请注明出处:https://ahangchen.gitbooks.io/chromium_doc_zh/content/zh//General_Architecture/Plugin_A ...

  4. Python:开发Sublime插件,方便PHP开发

    Python:开发Sublime插件,方便PHP开发 背景 最近在学习PHP,开发环境选择了Sublime2,开发过程发现执行PHP程序非常不方便,需要自己在浏览器中输入路径以进行调试,这点不如Dre ...

  5. C++插件架构浅谈与初步实现

    一.插件架构初步介绍 想到写本博客,也没想到更好的名字,目前就先命这个名吧.说到插件架构,或许大部分IT从业者都听过或者某些牛人也自己实现过稳定高效的插件框架.目前有很多软件以及库都是基于插件架构,例 ...

  6. vim python自动补全插件:pydiction

    vim python自动补全插件:pydiction 可以实现下面python代码的自动补全: 1.简单python关键词补全 2.python 函数补全带括号 3.python 模块补全 4.pyt ...

  7. Mac Sublime Text 3 配置Python环境及安装插件

    一.下载安装Sublime Text 3 官网下载地址:http://www.sublimetext.com/3 二.配置Python开发环境 1.点击右下角,选择python 2.添加编译环境pyt ...

  8. DELPHI开发LINUX插件架构的程序

    DELPHI开发LINUX插件架构的程序 DELPHI可以开发LINUX配置型插件架构的程序,并且这一套插件架构,同样适用于MSWINDOWS和MAC. 配置插件: 根据配置,动态加载插件:

  9. 咏南跨平台中间件支持LINUX和WINDOWS插件架构

    咏南跨平台中间件支持LINUX和WINDOWS插件架构

随机推荐

  1. Chained Declustering

          此论文描述了在无共享架构的多处理器机器上的数据库系统的数据冗余分布方法.该方法提高了系统的可用性,同时在单节点故障的情况下,可以很好的实现负载均衡.以下是论文的一些摘要,详细可以参见论文原 ...

  2. 【SPL标准库专题(6)】 Datastructures:SplPriorityQueue

    普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头取出.在优先队列中,元素被赋予优先级.当访问元素时,具有最高优先级的元素最先取出.优先队列具有最高级先出 (largest-in,fir ...

  3. Oracle EBS FTP显示无法与某IP 连接

    首先 用root用户登录 如果可以登录 那么应该是权限的问题 这里选择 方法二:修改 /etc/sudoers 文件,找到下面一行,在root下面添加一行,如下所示: ## Allow root to ...

  4. "System.OutOfMemoryException" exception when you execute a query in SQL Server Management Studio (转自MSDN)

    Symptoms When you use Microsoft SQL Server Management Studio (SSMS) to run an SQL query that returns ...

  5. 4种更快更简单实现Python数据可视化的方法

    数据可视化是数据分析或机器学习项目中十分重要的一环.通常,你需要在项目初期进行探索性的数据分析(EDA),从而对数据有一定的了解,而且创建可视化确实可以使分析的任务更清晰.更容易理解,特别是对于大规模 ...

  6. Windows Server 2012 R2 创建AD域

        前言 我们按照下图来创建第一个林中的第一个域.创建方法为先安装一台Windows服务器,然后将其升级为域控制器.然后创建第二台域控制器,一台成员服务器与一台加入域的Win8计算机. 环境 网络 ...

  7. 点击一个div ,把div里的某个参数的值,传到一个input里面

    ​​​

  8. Qt分页导航控件

    最近在使用QTableWidget时,因为结果数量比较多而且又有单元格控件,为了改善效率要做分页处理.在网上找了一番,最后在http://www.cppblog.com/biao/archive/20 ...

  9. Mysql双主 keepalived+lvs实现mysql高可用性

    MySQL复制 能够保证数据的冗余的同时可以做读写分离来分担系统压力,如果是主主复制还可以很好的避免主节点的单点故障.但是MySQL主主复制存在一些问题无法满足我们的实际需要:未提供统一访问入口来实现 ...

  10. Android 一s个相对完整的自动升级功能实现代码

    由于项目的需要最近做了一个关于Android自动升级的功能,下面将贴出Android手机客户端的完整代码.这段代码参考别的代码居多,由于不满足需求,所以自己仅仅改了一些需要变动的内容,其他功能都是按照 ...