在系统设计中,经常我们希望设计一套插件机制,在不修改程序主体情况下,动态去加载附能。

我设想的插件系统:

1、通过类来实现

2、自动查找和导入

我们假设需要实现一个简单的插件系统,插件可以接收一个参数执行。

实现基础插件类

我们先构建一个基础插件类:plugin_collection.py

class Plugin:

"""

该基类每个插件都需要继承,插件需要实现基类定义的方法"""

def __init__(self):

self.description = '未知'

def perform_operation(self, argument):

"""

实际执行插件所执行的方法,该方法所有插件类都需要实现

"""

raise NotImplementedError

所有的插件类需要申明description来进行插件描述,并且要实现perform_operation方法,该方法是实际加载插件将去执行的方法。

简易插件

我们现在实现一个插件,实际执行时仅返回传入的参数: plugins/identity.py

import plugin_collection

class Identity(plugin_collection.Plugin):

"""

This plugin is just the identity function: it returns the argument

"""

def __init__(self):

super().__init__()

self.description = 'Identity function'

def perform_operation(self, argument):

"""

The actual implementation of the identity plugin is to just return the

argument

"""

return argument

动态加载机制

因为我们预实现动态加载插件。我们通过定义一个PluginCollection来完成该职责,它将载入所有的插件,并且根据传入的值执行perform_operation方法。PluginCollection类基础组件实现如下:plugins_collection.py

class PluginCollection:

"""

该类会通过传入的package查找继承了Plugin类的插件类

"""

def __init__(self, plugin_package):

self.plugin_package = plugin_package

self.reload_plugins()

def reload_plugins(self):

"""

重置plugins列表,遍历传入的package查询有效的插件

"""

self.plugins = []

self.seen_paths = []

print()

print(f"在 {self.plugin_package} 包里查找插件")

self.walk_package(self.plugin_package)

def apply_all_plugins_on_value(self, argument):

print()

print(f"执行参数 {argument} 到所有的插件:")

for plugin in self.plugins:

print(f" 执行 {plugin.description} 参数 {argument} 结果 {plugin.perform_operation(argument)}")

最关键的是PluginCollection类里的walk_package方法,该方法按如下步骤操作:

1、操作package里所有的模块

2、针对找到的模块,检查是否是Plugin的子类,非Plugin自身。每个插件将会初始化并加入到列表。该检查的好处是你可以放入其他Python模块,也并不影响插件的使用

3、检查当前package下的子目录,递归查找插件

def walk_package(self, package):

"""

递归遍历包里获取所有的插件

"""

imported_package = __import__(package, fromlist=['blah'])

for _, pluginname, ispkg in pkgutil.iter_modules(imported_package.__path__, imported_package.__name__ + '.'):

if not ispkg:

plugin_module = __import__(pluginname, fromlist=['blah'])

clsmembers = inspect.getmembers(plugin_module, inspect.isclass)

for (_, c) in clsmembers:

# 仅加入Plugin类的子类,忽略掉Plugin本身

if issubclass(c, Plugin) and (c is not Plugin):

print(f' 找到插件类: {c.__module__}.{c.__name__}')

self.plugins.append(c())

# 现在我们已经查找了当前package中的所有模块,现在我们递归查找子packages里的附件模块

all_current_paths = []

if isinstance(imported_package.__path__, str):

all_current_paths.append(imported_package.__path__)

else:

all_current_paths.extend([x for x in imported_package.__path__])

for pkg_path in all_current_paths:

if pkg_path not in self.seen_paths:

self.seen_paths.append(pkg_path)

# 获取当前package中的子目录

child_pkgs = [p for p in os.listdir(pkg_path) if os.path.isdir(os.path.join(pkg_path, p))]

# 递归遍历子目录的package

for child_pkg in child_pkgs:

self.walk_package(package + '.' + child_pkg)

测试

现在我们写个简单的测试:test.py

from plugin_collection import PluginCollection

my_plugins = PluginCollection('plugins')

my_plugins.apply_all_plugins_on_value(5)

执行结果:

$ python3 test.py

在 plugins 包里查找插件

找到插件类: plugins.identity.Identity

执行参数 5 到所有的插件:

执行 Identity function 参数 5 结果 5

python所有插件框架_Python中实现简单的插件框架相关推荐

  1. python算法和数据结构_Python中的数据结构和算法

    python算法和数据结构 To 至 Leonardo da Vinci 达芬奇(Leonardo da Vinci) 介绍 (Introduction) The purpose of this ar ...

  2. python连接池框架_Python中的连接池是非常重要的!神级程序员详解!

    概述 连接池的作用就是为了提高性能,将已经创建好的连接保存在池中,当有请求来时,直接使用已经创建好的连接对Server端进行访问.这样 省略了创建连接和销毁连接的过程(TCP连接建立时的三次握手和销毁 ...

  3. python绝对值编程_python中取绝对值简单方法总结

    python如何使用绝对值?下面给大家介绍三种求绝对值的方法: import math def abs_value1(): a = float(input('1.请输入一个数字:')) if a &g ...

  4. python求绝对值_python中取绝对值简单方法总结

    python如何使用绝对值?下面给大家介绍三种求绝对值的方法: import math def abs_value1(): a = float(input('1.请输入一个数字:')) if a &g ...

  5. python中绝对值怎么表示_python中取绝对值简单方法总结

    python如何使用绝对值?下面给大家介绍三种求绝对值的方法: import math def abs_value1(): a = float(input('1.请输入一个数字:')) if a &g ...

  6. python加绝对值_python中取绝对值简单方法总结

    python如何使用绝对值?下面给大家介绍三种求绝对值的方法: import math def abs_value1(): a = float(input('1.请输入一个数字:')) if a &g ...

  7. 绝对值在python中怎么打出来_python中取绝对值简单方法总结

    python中取绝对值简单方法总结,绝对值,请输入,数字,值为,方法 python中取绝对值简单方法总结 易采站长站,站长之家为您整理了python中取绝对值简单方法总结的相关内容. python如何 ...

  8. python基础知识测试题_Python中的单元测试—基础知识

    python基础知识测试题 Unit testing is the number one skill which separates people who just finished their de ...

  9. python怎么调用文件_python 中如何引用头文件

    python 引入 导入 自定义模块, python 引入 导入 外部文件 python 引入 导入 自定义模块, python 引入  导入 外部文件 项目中想使用以前的代码,或者什么样的需求致使你 ...

最新文章

  1. rust怎么用items刷东西_装修贷卡怎么刷?不同银行的用不同的POS机刷才对
  2. Java I/O不迷茫,一文为你导航!
  3. 数据结构-排序(插入排序)
  4. C# 实现 rtc_通过Xlua实现unity热更新的一个小例子
  5. 《深入浅出DPDK》学习思维导图
  6. Struts2中的国际化
  7. mysql 表字段部分替换
  8. JSON解析(C++)
  9. 高德地图轨迹方向_阿里巴巴高德地图首席科学家任小枫:高精算法推动高精地图落地...
  10. vscode中文乱码问题及几种常见的解决方案
  11. 林熙蕾和吴大维分手,和元大小开马维辰交往,真实性有待考验
  12. 教师资格考试科目二 word Exele ppt 应用
  13. 解决图片闪烁问题(雪碧图)
  14. 安卓无线打印服务器,安卓 打印服务器
  15. 瑞莎 Renesas Flash烧录
  16. js html页面切换效果,jQuery实现切换页面过渡动画效果
  17. PADS9.5使用笔记(常用功能和疑难问题)
  18. Javascript frameworks
  19. discuz db_mysql.calss.php_刚发现得好东西!discuz 7.0 db_mysql.php 详解
  20. (NYoj 304) 节能 --区间DP

热门文章

  1. 《漫画算法2》源码整理-7 第K大的数字
  2. 惊艳的cygwin——Windows下的Linux命令行环境的配置和使用
  3. Tomcat原理详解和各种集群的实现
  4. 《卓有成效的程序员》----读书笔记一
  5. 谈一谈CMU导师和学生的互动方式
  6. Python 的闭包和装饰器
  7. 深度学习(一)深度学习学习资料
  8. C语言中 if 和 else if 的区别
  9. JavaScript复制内容到剪贴板
  10. Java算法-奇怪的分式