近日,决定用 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. show命令

    数据库 show databases; 表 show tables; show tables in xxdb; show tables 'a*'; tblproperties show tblprop ...

  2. MySQL缓存机制详解(一)

    本文章拿来学习用||参考资料:http://www.2cto.com/database/201308/236361.html 对MySql查询缓存及SQL Server过程缓存的理解及总结   一.M ...

  3. selenium 校验文件下载成功

    转自: http://www.seleniumeasy.com/selenium-tutorials/verify-file-after-downloading-using-webdriver-jav ...

  4. Oracle EBS INV 创建物料搬运单行

    CREATE OR REPLACE PROCEDURE CreateMoveOrderLines AS -- Common Declarations l_api_version NUMBER := 1 ...

  5. MySQL binlog group commit--commit stage

    说明: 1.process_commit_stage_queue:调用调用ha_commit_low->innobase_commit进入innodb层依次提交 2. process_after ...

  6. The 10 Best Neighborhoods in Seattle

    https://www.seattlemet.com/articles/2015/4/24/the-10-best-neighborhoods-in-seattle-may-2015 By Darre ...

  7. Azure IoT 预配置解决方案

    Azure IoT 预配置解决方案 Sangyu Li © 2018  一.什么是Azure IoT 预配置解决方案? 如图,这就是Azure IoT Suite中 Provision solutio ...

  8. October 24th, 2017 Week 43rd Tuesday

    We can't give up trying. The fight was worth it. 我们不能放弃尝试,奋斗是值得的. When doing researches in some cutt ...

  9. PyQt5--MenuBar

    # -*- coding:utf-8 -*- ''' Created on Sep 13, 2018 @author: SaShuangYiBing ''' import sys from PyQt5 ...

  10. sublime设置node.js编译

    1. 首先需安装node环境并配置好环境变量,安装教程. 2. 然后在sublime中打开工具(Tools)→编译系统(Build System)→新编译系统(New Build System) 3. ...