当前位置: 首页 > article >正文

Python 实现最小插件框架

文章目录

  • Python 实现最小插件框架
    • 1. 基础实现
      • 项目结构
      • plugin_base.py - 插件基类
      • plugins/hello.py - 示例插件1
      • plugins/goodbye.py - 示例插件2
      • main.py - 主程序
    • 2. 更高级的特性扩展
      • 2.1 插件配置支持
      • 2.2 插件依赖管理
      • 2.3 插件热加载
    • 3. 使用 setuptools 的入口点发现插件
      • 3.1 修改项目结构
      • 3.2 setup.py 示例
      • 3.3 修改插件管理器
    • 4. 插件隔离(使用importlib)
    • 5. 最小完整示例(无目录结构要求)

Python 实现最小插件框架

一个非常简洁但功能完整的 Python 插件框架实现,这个框架具有以下特点:

  • 动态加载插件
  • 插件自动发现
  • 简单的插件接口
  • 支持插件隔离

1. 基础实现

项目结构

my_app/
├── main.py         # 主程序
├── plugins/        # 插件目录
│   ├── __init__.py
│   ├── hello.py    # 示例插件
│   └── goodbye.py  # 示例插件
└── plugin_base.py  # 插件基类

plugin_base.py - 插件基类

import abcclass PluginBase(abc.ABC):"""所有插件的基类"""@classmethod@abc.abstractmethoddef initialize(cls):"""插件初始化方法"""pass@abc.abstractmethoddef execute(self, *args, **kwargs):"""插件执行方法"""pass

plugins/hello.py - 示例插件1

from plugin_base import PluginBaseclass HelloPlugin(PluginBase):@classmethoddef initialize(cls):print("HelloPlugin initialized")return cls()def execute(self, name="World"):print(f"Hello, {name}!")

plugins/goodbye.py - 示例插件2

from plugin_base import PluginBaseclass GoodbyePlugin(PluginBase):@classmethoddef initialize(cls):print("GoodbyePlugin initialized")return cls()def execute(self, name="World"):print(f"Goodbye, {name}!")

main.py - 主程序

import importlib
import pkgutil
from pathlib import Path
from plugin_base import PluginBaseclass PluginManager:def __init__(self):self.plugins = {}def discover_plugins(self, plugin_dir="plugins"):"""自动发现插件"""plugin_path = Path(plugin_dir)# 遍历插件目录for finder, name, _ in pkgutil.iter_modules([str(plugin_path)]):try:module = importlib.import_module(f"{plugin_dir}.{name}")for item in dir(module):obj = getattr(module, item)if (isinstance(obj, type)and issubclass(obj, PluginBase)and obj != PluginBase):self.plugins[name] = objprint(f"Found plugin: {name}")except ImportError as e:print(f"Failed to import plugin {name}: {e}")def initialize_plugins(self):"""初始化所有插件"""return {name: plugin.initialize()for name, plugin in self.plugins.items()}if __name__ == "__main__":manager = PluginManager()manager.discover_plugins()plugins = manager.initialize_plugins()# 使用插件plugins["hello"].execute("Python")plugins["goodbye"].execute("Python")

2. 更高级的特性扩展

如果你想增强这个框架,可以考虑添加以下特性:

2.1 插件配置支持

修改 plugin_base.py:

class PluginBase(abc.ABC):@classmethod@abc.abstractmethoddef initialize(cls, config=None):"""支持传入配置"""pass

2.2 插件依赖管理

在插件类中添加:

class HelloPlugin(PluginBase):REQUIRED_PLUGINS = ['some_dependency']@classmethoddef initialize(cls):# 检查依赖pass

2.3 插件热加载

添加热加载方法:

def reload_plugin(self, plugin_name):"""重新加载插件"""if plugin_name in self.plugins:module = importlib.import_module(f"plugins.{plugin_name}")importlib.reload(module)self.plugins[plugin_name] = getattr(module, plugin_name.capitalize() + "Plugin")

3. 使用 setuptools 的入口点发现插件

更Pythonic的方式是使用setuptools的entry_points:

3.1 修改项目结构

my_app/
├── setup.py
├── my_app/
│   ├── __init__.py
│   ├── main.py
│   └── plugin_base.py
└── plugins/├── hello.py└── goodbye.py

3.2 setup.py 示例

from setuptools import setup, find_packagessetup(name="my_app",version="0.1",packages=find_packages(),entry_points={'my_app.plugins': ['hello = plugins.hello:HelloPlugin','goodbye = plugins.goodbye:GoodbyePlugin',],},
)

3.3 修改插件管理器

from importlib.metadata import entry_pointsclass PluginManager:def discover_plugins(self):"""使用entry_points发现插件"""discovered_plugins = entry_points(group='my_app.plugins')for ep in discovered_plugins:try:plugin_class = ep.load()if (isinstance(plugin_class, type)and issubclass(plugin_class, PluginBase)and plugin_class != PluginBase):self.plugins[ep.name] = plugin_classexcept Exception as e:print(f"Failed to load plugin {ep.name}: {e}")

4. 插件隔离(使用importlib)

如果需要更强的隔离,可以这样加载插件:

def load_plugin_with_isolation(plugin_path):"""隔离加载插件"""spec = importlib.util.spec_from_file_location("isolated_plugin", plugin_path)module = importlib.util.module_from_spec(spec)sys.modules["isolated_plugin"] = modulespec.loader.exec_module(module)return module

5. 最小完整示例(无目录结构要求)

如果你想要一个真正最小化的实现(单文件):

# mini_plugin.py
import importlib
from pathlib import Pathclass Plugin:def execute(self):raise NotImplementedErrorclass PluginManager:def __init__(self):self.plugins = {}def load_plugin(self, plugin_path):module_name = Path(plugin_path).stemspec = importlib.util.spec_from_file_location(module_name, plugin_path)module = importlib.util.module_from_spec(spec)spec.loader.exec_module(module)for name in dir(module):obj = getattr(module, name)if isinstance(obj, type) and issubclass(obj, Plugin) and obj is not Plugin:self.plugins[module_name] = obj()return obj()return Noneif __name__ == "__main__":manager = PluginManager()plugin = manager.load_plugin("hello_plugin.py")  # 假设同级目录下有这个文件if plugin:plugin.execute()

配套的最简插件文件 hello_plugin.py:

from mini_plugin import Pluginclass HelloPlugin(Plugin):def execute(self):print("Hello from minimal plugin!")

这个最小实现只有不到30行代码,但包含了插件框架的核心功能。

相关文章:

Python 实现最小插件框架

文章目录 Python 实现最小插件框架1. 基础实现项目结构plugin_base.py - 插件基类plugins/hello.py - 示例插件1plugins/goodbye.py - 示例插件2main.py - 主程序 2. 更高级的特性扩展2.1 插件配置支持2.2 插件依赖管理2.3 插件热加载 3. 使用 setuptools 的入口点发现插件3.1 …...

内网邮箱服务器搭建-详解

目录 一、背景 二、搭建邮箱需要具备的基础知识 1、smtp(Simple Mail Transfer Protocol) SMTP工作原理 SMTP 命令 SMTP 协议端口 2、pop3(Post Office Protocol) POP3特点 POP3工作原理 3、imap4(Internet M…...

21 天 Python 计划:使用SQLAlchemy 中的ORM查询

文章目录 准备工作图书表 books分类表 categoriesORM 对象定义 一、根据主键获取记录二、AND 查询三、 常用方法四、OR 查询五、 5. AND 和 OR 并存的查询六、巧用列表或者字典的解包给查询方法传参七、其它常用运算符八、查询指定列九、内连接、外连接9.1 内连接9.2 外连接9.3…...

使用 LLaMA-Factory 微调 llama3 模型(二)

使用 LLaMA-Factory 微调 llama3 模型 1. LLaMA-Factory模型介绍 https://github.com/hiyouga/LLaMA-FactoryLLaMA-Factory 是一个用于大型语言模型(LLM)微调的工具,它旨在简化大型语言模型的微调过程, 使得用户可以快速地对模型…...

并发编程--条件量与死锁及其解决方案

并发编程–条件量与死锁及其解决方案 文章目录 并发编程--条件量与死锁及其解决方案1.条件量1.1条件量基本概念1.2条件量的使用 2. 死锁 1.条件量 1.1条件量基本概念 在许多场合中,程序的执行通常需要满足一定的条件,条件不成熟的时候,任务…...

JAVA SE 自我总结

目录 1. 字面常量 2. 数据类型 3. 变量 4. 类型转换 5. 实参和形参的关系 6. 数组 6.1 数组的概念 6.2 动态初始化 6.3 静态初始化 7. 数据区 ​编辑 8. 数组的拷贝 8.1 赋值拷贝 8.2 方法拷贝 9. 代码块 10. 内部类 10.1 实例内部类 10.2 静态内部类 10.3 …...

RAG创建向量数据库:docsearch = FAISS.from_texts(documents, embeddings)

RAG创建向量数据库:docsearch = FAISS.from_texts(documents, embeddings) 代码解释 docsearch = FAISS.from_texts(documents, embeddings) 这行代码主要作用是基于给定的文本集合创建一个向量数据库(这里使用 FAISS 作为向量数据库工具 )。具体说明如下: FAISS :FAISS …...

虚幻引擎5-Unreal Engine笔记之“将MyStudent变量设置为一个BP_Student的实例”这句话如何理解?

虚幻引擎5-Unreal Engine笔记之“将MyStudent变量设置为一个BP_Student的实例”这句话如何理解? code review! 文章目录 虚幻引擎5-Unreal Engine笔记之“将MyStudent变量设置为一个BP_Student的实例”这句话如何理解?理解这句话的关键点1.类&#xff08…...

鸢尾花分类的6种机器学习方法综合分析与实现

鸢尾花分类的6种机器学习方法综合分析与实现 首先我们来看一下对应的实验结果。 数据准备与环境配置 在开始机器学习项目前,首先需要准备编程环境和加载数据。以下代码导入必要的库并加载鸢尾花数据集: import numpy as np import pandas as pd impo…...

vite,Vue3,ts项目关于axios配置

一、安装依赖包 npm install axios -S npm install qs -S npm install js-cookie 文件目录 二、配置线上、本地环境 与src文件同级,分别创建本地环境文件 .env.development 和线上环境文件 .env.production # 本地环境 ENV = development # 本地环境接口地址 VITE_API_URL =…...

mysql:重置表自增字段序号

情况一:清空表数据后重置自增 ID 如果你希望清空表中的所有数据,并将自增 ID 重置为初始值(通常为 1) 1、truncate truncate table tb_dict; 2、delete 配合 alter 语句 delete from tb_dict; alter table tb_dict AUTO_INCR…...

STM32 模块化开发指南 · 第 4 篇 用状态机管理 BLE 应用逻辑:分层解耦的实践方式

本文是《STM32 模块化开发实战指南》第 4 篇,聚焦于 BLE 模块中的状态管理问题。我们将介绍如何通过有限状态机(Finite State Machine, FSM)架构,实现 BLE 广播、扫描、连接等行为的解耦与可控,并配合事件队列驱动完成主从共存、低功耗友好、状态清晰的 BLE 应用。 一、为…...

HTML — 浮动

浮动 HTML浮动(Float)是一种CSS布局技术,通过float: left或float: right使元素脱离常规文档流并向左/右对齐,常用于图文混排或横向排列内容。浮动元素会紧贴父容器或相邻浮动元素的边缘,但脱离文档流后可能导致父容器高…...

IP节点详解及国内IP节点获取指南

获取国内IP节点通常涉及网络技术或数据资源的使用,IP地址作为网络设备的唯一标识,对于网络连接和通信至关重要。详细介绍几种修改网络IP地址的常用方法,无论是对于家庭用户还是企业用户,希望能找到适合自己的解决方案。以下是方法…...

AD9253 LVDS 高速ADC驱动开发

1、查阅AD9253器件手册 2、查阅Xilinx xapp524手册 3、该款ADC工作在125Msps下,14bit - 2Lane - 1frame 模式。 对应:data clock时钟为500M DDR mode。data line rate:1Gbps。frame clock:1/4 data clock 具体内容:…...

pycharm2024.3.5版本配置conda踩坑

配置解释器是conda时,死活选不到自己的环境 看了很多,都是说要选scripts下的conda.exe 都没用 主要坑在于这是新版的pycharm 是配置condabin 下的 conda.bat 参考:PyCharm配置PyTorch环境(完美解决找不到Conda可执行文件python.exe问题) …...

【异常处理】Clion IDE中cmake时头文件找不到 头文件飘红

如图所示是我的clion项目目录 我自定义的data_structure.h和func_declaration.h在unit_test.c中无法检索到 cmakelists.txt配置文件如下所示: cmake_minimum_required(VERSION 3.30) project(noc C) #设置头文件的目录 include_directories(${CMAKE_SOURCE_DIR}/…...

14 - VDMA彩条显示实验

文章目录 1 实验任务2 系统框图3 硬件设计4 软件设计 1 实验任务 本实验任务是PS端写彩条数据至DDR3内存中,然后通过PL端的VDMA IP核将彩条数据通过HDMI接口输出显示。 2 系统框图 本实验是用HDMI接口固定输出1080P的彩条图,所以: rgb2lc…...

每天学一个 Linux 命令(13):touch

Linux 文件管理命令:touch touch 是 Linux 中一个简单但高频使用的命令,主要用于创建空文件或修改文件的时间戳(访问时间、修改时间)。它是文件管理和脚本操作的实用工具。 1. 命令作用 创建空文件:快速生成一个或多个空白文件。更新时间戳:修改文件的访问时间(Access …...

PromptUp 网站介绍:AI助力,轻松创作

1. 网站定位与核心功能 promptup.net 可能是一个面向 创作者、设计师、营销人员及艺术爱好者 的AI辅助创作平台,主打 零门槛、智能化的内容生成与优化。其核心功能可能包括: AI艺术创作:通过输入关键词、选择主题或拖放模板,快速生成风格多样的数字艺术作品(如插画、海报…...

高级java每日一道面试题-2025年3月26日-微服务篇[Nacos篇]-在Spring Cloud项目中如何集成Nacos?

如果有遗漏,评论区告诉我进行补充 面试官: 在Spring Cloud项目中如何集成Nacos? 我回答: 在Spring Cloud项目中集成Nacos,可以充分利用Nacos作为服务注册与发现中心以及配置管理中心的功能。以下是详细的步骤和说明,帮助你完成这一集成过程…...

AI 大语言模型 (LLM) 平台的整体概览与未来发展

📋 分析报告:AI 大语言模型 (LLM) 平台的整体概览与未来发展 自动生成的结构化分析报告 💻 整体概述:AI LLM 平台的市场现状与发展动力 随着人工智能技术的飞速发展,大语言模型(Large Language Models, L…...

Java中的Map vs Python字典:核心对比与使用指南

一、核心概念 1. 基本定义 Python字典(dict) :动态类型键值对集合,语法简洁,支持快速查找。Java Map:接口,常用实现类如 HashMap、LinkedHashMap,需声明键值类型(泛型&…...

人工智能100问☞第3问:深度学习的核心原理是什么?

目录 一、通俗解释 二、专业解析 三、权威参考 深度学习的核心原理是​​通过构建多层神经网络结构,逐层自动提取并组合数据特征,利用反向传播算法优化参数,从而实现对复杂数据的高层次抽象和精准预测​​。 一、通俗解释 ​​深度学习的核心原理,就像是教计算机像婴儿…...

金能电力:配电房为什么离不开绝缘胶板

在当今电力系统日益复杂、对供电稳定性与安全性要求极高的时代,每一个细节都关乎着电力供应的顺畅以及工作人员的生命安全。而配电房里常常被大家忽视的绝缘垫,实则起着至关重要的 “守护” 作用。今天,金能电力就来给大家详细讲讲配电房为什…...

Python 深度学习实战 第1章 什么是深度学习代码示例

第1章:什么是深度学习 内容概要 第1章介绍了深度学习的背景、发展历史及其在人工智能(AI)和机器学习(ML)中的地位。本章探讨了深度学习的定义、其与其他机器学习方法的关系,以及深度学习在近年来取得的成…...

【模块化拆解与多视角信息1】基础信息:隐藏的筛选规则——那些简历上没说出口的暗号

写在最前 作为一个中古程序猿,我有很多自己想做的事情,比如埋头苦干手搓一个低代码数据库设计平台(目前只针对写java的朋友),比如很喜欢帮身边的朋友看看简历,讲讲面试技巧,毕竟工作这么多年,也做到过高管,有很多面人经历,意见还算有用,大家基本都能拿到想要的offe…...

【HD-RK3576-PI】VNC 远程桌面连接

在当今数字化时代,高效便捷的操作方式是技术爱好者与专业人士的共同追求。对于使用 HD-RK3576-PI微型单板计算机的用户而言,当面临没有显示屏的场景时,如何实现远程操作桌面系统呢?别担心,VNC 远程桌面连接将为你解决这…...

Vue.js 中 v-if 的使用及其原理

在 Vue.js 的开发过程中,条件渲染是一项极为常见的需求。v-if指令作为 Vue.js 实现条件渲染的关键手段,能够根据表达式的真假来决定是否渲染某一块 DOM 元素。它在优化页面展示逻辑、提升用户体验等方面发挥着重要作用。接下来,我们就深入探讨…...

电梯广告江湖的终局:分众 “吃掉” 新潮,是救赎还是迷途?

文 / 大力财经 作者 / 魏力 导言:商业世界的底层运行法则,从来都是能量流动的自然映射。宇宙第一性原理和运行法则是,能量大的吸引能量小的。电梯里的战争与和平,从对抗到合并,成为中国商业竞争史中关于博弈与进化的…...