我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Python中实现简单的插件框架

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Python中实现简单的插件框架

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

plugin

我设想的插件系统:

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

代码:https://github.com/erhuabushuo/plugin_template

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Python中实现简单的插件框架

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Python中实现简单的插件框架

在系统设计中,经常我们希望设计一套插件机制,在不修改程序主体情况下,动态去加载附能。我设想的插件系统:1、通过类来实现2、自动查找和导入我们假设需要实现一个简单的插件系统,插件可以接收一个参数执行。实现基础插件类我们先构建一个基础插件类:p
2023-01-30

使用Python实现简单的爬虫框架

爬虫是一种自动获取网页内容的程序,它可以帮助我们从网络上快速收集大量信息。下面我们将学习如何使用Python编写一个简单的爬虫框架,感兴趣的可以了解一下
2023-05-19

python实现一个简单的web应用框架

这篇文章主要为大家介绍了使用python写一个简单的web应用框架实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-05-18

怎样实现简单的RPC框架

怎样实现简单的RPC框架,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。1.定义上下文对象在RpcContext对象中增加一个map类型的参数对象,可以存放任意扩展的参数。2.R
2023-06-04

python的简单web框架flask快速实现详解

这篇文章主要为大家介绍了python的简单web框架flask快速实现详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-02-07

使用Python的Flask框架表单插件Flask-WTF实现Web登录验证

表单是让用户与我们的网页应用程序交互的基本元素。Flask 本身并不会帮助我们处理表单,但是 Flask-WTF 扩展让我们在我们的 Flask 应用程序中使用流行的 WTForms 包。这个包使得定义表单和处理提交容易一些。 Flask-
2022-06-04

如何在Python中实现一个简单的RPC远程过程调用框架

如何在Python中实现一个简单的RPC远程过程调用框架在分布式系统中,一种常见的通信机制是通过RPC(Remote Procedure Call,远程过程调用)来实现不同进程之间的函数调用。RPC允许开发者像调用本地函数一样调用远程函数,
2023-10-27

Eclipse中的Jobs框架的简单介绍

这篇文章主要讲解了“Eclipse中的Jobs框架的简单介绍”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Eclipse中的Jobs框架的简单介绍”吧!了解Eclipse多线程机制,需要先了
2023-06-17

Python流行ORM框架sqlalchemy的简单使用

安装 http://docs.sqlalchemy.org 1、安装#进入虚拟环境 #执行 ./python3 -m pip installimport sqlalchemy print(sqlalchemy.__version__) #
2022-06-02

Go语言Http Server框架实现一个简单的httpServer

这篇文章主要为大家介绍了Go语言Http Server框架实现一个简单的httpServer抽象,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-05-18

Android中网络框架简单封装的实例方法

Android中网络框架的简单封装 前言 Android作为一款主要应用在移动终端的操作系统,访问网络是必不可少的功能。访问网络,最基本的接口有:HttpUrlConnection,HttpClient,而在后续的发展中,出现了Volley
2022-06-06

Python的Scrapy爬虫框架简单学习笔记

一、简单配置,获取单个网页上的内容。 (1)创建scrapy项目scrapy startproject getblog(2)编辑 items.py# -*- coding: utf-8 -*-# Define here the models
2022-06-04

Python的Flask开发框架简单上手笔记

最简单的hello world#!/usr/bin/env python # encoding: utf-8from flask import Flask app = Flask(__name__)@app.route('/') def i
2022-06-04

如何用Python写一个简单的Web框架

如何用Python写一个简单的Web框架,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。一、概述在Python中,WSGI(Web Server Gateway
2023-06-17

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录