python 优雅地实现插件架构

简介: 近日,决定用 python 实现插件架构,于是上 stackoverflow 逛了一下,在这里发现一段代码,非常喜欢。提醒各位大侠注意,我对这段代码作了一点小小的改动:原 PLUGINS 是 list 对象,改动后 PLUGINS 是 dict 对象。

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

优化方向

  • 热插拔
  • 懒加载
目录
相关文章
|
3月前
|
开发者 Python
Python 的主流版本:Python 3.x
Python 的主流版本:Python 3.x
111 2
|
7月前
|
数据挖掘 测试技术 开发工具
python 以及集成环境的安装
python 以及集成环境的安装
|
小程序 iOS开发 Python
Python基础小项目
今天给大家写一期特别基础的Python小项目,欢迎大家支持,并给出自己的完善修改 (因为我写的都是很基础的,运行速率不是很好的
46 0
|
数据安全/隐私保护 Python
Python 工具包发布
首先,我们可以创建一个 Python 工具包,比如叫做 mypackage,它包含一个模块 mymodule 和一个函数 hello,用于输出 Hello, world!。目录结构如下:
437 1
|
XML 安全 Unix
Python3.7升级Python3.8(Python3.8新特性调研)
Python3.7升级Python3.8(Python3.8新特性调研)
352 0
|
网络安全 API 开发工具
【Python】【应用】Python应用之玩转gerrit系列之一——搭建基础环境
【Python】【应用】Python应用之玩转gerrit系列之一——搭建基础环境
909 0
【Python】【应用】Python应用之玩转gerrit系列之一——搭建基础环境
|
Linux C语言 Python
|
开发框架 物联网 Java
如何给Python轻应用添加新的组件:Python轻应用扩展适配介绍
如何给Python轻应用添加新的组件:Python轻应用扩展适配介绍
如何给Python轻应用添加新的组件:Python轻应用扩展适配介绍
|
Ubuntu Python
python3.5项目升级3.8问题汇总
服务器:Ubuntu 16.04.4 LTS 当前Python版本:3.5.2 待升级Python版本:3.8.x 项目框架:Django2.0.9
|
机器学习/深度学习 存储 人工智能
Python为什么流行?Python代码能实现哪些有趣的功能
Python为什么流行?Python代码能实现哪些有趣的功能
2156 0