python插件架构介绍

一、插件架构

在 Python 中,插件架构通常指的是一种软件架构模式,它允许开发者在不改变主应用程序代码的情况下,向应用程序添加新的功能或修改现有功能。这种架构使得应用程序可以通过加载外部模块或组件来扩展其功能,这些外部模块或组件通常被称为“插件”。

Python 的插件架构涉及以下几个关键点:

模块化:Python 支持模块化设计,意味着应用程序可以被分解成独立、可替换、可重用的模块。插件本质上是这些模块的一种,它们遵循预定义的接口或协议。接口定义:为了让插件能够与主应用程序交互,通常会定义一套接口或抽象基类。插件需要实现这些接口或继承并实现这些基类,从而提供必要的功能。插件发现:应用程序需要有某种机制来发现可用的插件。这可以通过扫描特定目录、注册表项或使用插件管理器来实现。插件发现过程可能涉及动态加载 Python 模块。插件加载与激活:一旦发现一个插件,应用程序需要知道如何加载并激活它。在 Python 中,这通常涉及到使用标准库中的 importlib 模块动态加载插件模块,并创建插件实例。配置和定制:插件系统应该允许插件通过配置文件或环境变量等方式进行定制,以满足不同用户或不同环境的需求。隔离和安全性:合理的插件架构应该确保插件之间以及插件与主应用程序之间有适当的隔离,以保护应用程序的整体安全性和稳定性。

Python 中实现插件架构的例子包括:

使用 setuptools 的 entry points:setuptools 提供了 entry points 机制,这是一种用于发现和加载插件的方法。开发者可以在 setup.py 文件中指定 entry points,然后在应用程序中通过 pkg_resources 或 importlib.metadata(Python 3.8+)来发现和加载符合 entry points 的模块。使用专门的插件框架:如 pluggy(pytest 用它实现了插件系统)、yapsy、pluginbase 等。这些框架提供了插件的发现、加载和管理的更高级抽象。自定义插件架构:开发者也可以根据自己的需求实现自定义的插件系统。这可能包括定义接口、编写插件加载机制和管理工具等。利用插件架构,Python 应用程序可以变得更加灵活和可扩展,更容易适应不断变化的需求。

二、以pluggy模块,给一个代码案例

pluggy 是一个插件管理框架,它是由 pytest 团队开发的,用于构建可扩展的应用程序。以下是使用 pluggy 构建一个简单插件系统的代码示例:

首先,你需要安装 pluggy。可以使用 pip 进行安装:

pip install pluggy

步骤 1: 定义钩子规范

钩子规范是接口的声明,它定义了插件需要实现的方法和所需的参数。这些规范是插件开发者遵循的蓝图,确保了所有插件都有一致的接口。

# hookspecs.py
import pluggy# 创建一个钩子规范管理器
hookspec = pluggy.HookspecMarker("myproject")class MySpec:"""一个包含所有钩子规范的类。"""@hookspecdef my_hook(self, arg1, arg2):"""一个简单的钩子规范,插件需要实现这个接口。"""pass

步骤 2: 实现插件

开发者根据钩子规范创建插件,提供具体的实现逻辑。

# plugins.py
import pluggyhookimpl = pluggy.HookimplMarker("myproject")class MyPlugin:"""一个插件实现,它实现了 my_hook 钩子。"""@hookimpldef my_hook(self, arg1, arg2):print(f"插件被调用,参数为:{arg1}, {arg2}")# 在这里执行插件的功能逻辑return arg1 + arg2

步骤 3: 注册钩子规范、注册插件、调用钩子

接下来,我们需要告诉插件管理器(PluginManager)有哪些钩子规范存在。这样,管理器才能知道哪些钩子可以被调用,以及它们应该接受哪些参数。

# main.py
import pluggy
import hookspecs
import plugins# 创建一个插件管理器
pm = pluggy.PluginManager("myproject")
# 将钩子规范注册到插件管理器中
pm.add_hookspecs(hookspecs.MySpec)
# 注册插件
pm.register(plugins.MyPlugin())# 调用插件
result = pm.hook.my_hook(arg1=10, arg2=20)
print(result)

在这个过程中:

钩子规范 提供了一个统一的调用接口。
插件管理器 负责维护插件和钩子的注册信息,并在需要时调用正确的插件。
插件 提供了钩子的具体实现。

这种模式的优点是,主程序不需要知道插件的具体实现细节,只需要按照钩子规范调用接口即可。这允许主程序和插件开发者独立工作,只要遵守共同的规范。此外,可以随时添加或移除插件,而不需要修改主程序的代码,这提高了程序的模块化和可扩展性。

你运行 main.py 文件时,它会创建一个插件管理器,向管理器注册钩子规范和插件,并调用 my_hook 钩子。插件的 my_hook 方法会被执行,并打印参数和返回结果。

这个例子非常简单,但它展示了 pluggy 的基本用法,包括钩子规范的定义、插件的实现和它们的注册与调用。在实践中,pluggy 可以用于构建复杂的插件化系统,例如 pytest 测试框架就是一个很好的例子。

三、与传统继承类的区别

本质上,钩子规范和插件系统与抽象基类(ABCs)和继承确实有一些共同之处,但也存在关键的差异。让我们来探讨一下这两种概念:

相似之处:

接口定义:

抽象基类定义了一组抽象方法,子类必须实现这些方法。钩子规范定义了一组钩子接口,插件必须实现这些接口。

封装和扩展性:

抽象基类允许通过创建新的子类来扩展功能。钩子允许通过添加新的插件来扩展功能。

多态性:

在基于继承的系统中,多态性允许程序在运行时根据实际的子类类型来调用相应的方法。在插件系统中,多态性允许程序在运行时根据注册的插件来调用相应的钩子实现。

差异之处:

松耦合与紧耦合:

继承通常产生紧耦合的关系,因为子类依赖于其基类的定义,且在编译时就确定了类之间的关系。钩子和插件系统提供了更加松耦合的关系,因为插件可以在运行时动态加载和卸载,不需要在编译时知道具体的实现。

组合和灵活性:

继承可能导致类层次结构变得复杂,而且一个子类只能继承自一个基类(在不支持多重继承的语言中)。插件系统允许以组合的方式将多个独立的插件组合在一起,每个插件可以独立地实现一个或多个钩子,为同一个钩子提供不同的行为。

动态性:

继承通常在编码阶段决定。类的结构在编译或解释之前就已经固定下来。钩子和插件系统更加动态,允许在应用程序运行时动态地添加、移除或替换插件。

隔离性:

继承中的子类通常可以访问基类的保护成员,这在某种程度上减少了隔离性。插件通常只能访问它们需要实现的钩子规范,不会与其他插件或主程序产生直接的依赖关系,从而保持了较高的隔离性。

综上所述,抽象基类和继承机制更适合于那些类结构和层次关系相对固定的场景,而钩子和插件系统提供了更高的灵活性和动态性,更适合于需要运行时扩展和修改的应用程序。两者都是解决代码复用和抽象的有效手段,但选择哪种方式取决于具体的设计需求和上下文环境。

有价值的资源:
https://developer.aliyun.com/article/308565
https://github.com/influxdata/telegraf

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/637355.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ROS2】实现自定义服务接口

1 定义服务接口 在之前创建的ROS接口功能包的基础上。 int32 num1 int32 num2 --- int32 num3 2 在CmakerLists.txt中增加如下语句,实现对服务接口的生成 # 为接口文件生成源代码 rosidl_generate_interfaces(${PROJECT_NAME}"msg/Student.msg""…

IP劫持的危害分析及应对策略

在当今数字化时代,网络安全问题备受关注,其中IP劫持是一种常见而危险的威胁。本文将深入探讨IP劫持的危害,并提供一些有效的应对策略。 第一部分:IP劫持的定义 IP劫持是指黑客通过各种手段获取并篡改目标IP地址的控制权&#xf…

vue3+vite:封装Svg组件

前言 在项目开发过程中,以svg图片引入时,会遇到当hover态时图片颜色修改的场景,我们可能需要去引入另一张不同颜色的svg图片,或者用css方式修改,为了方便这种情况,需要封装svg组件来自定义宽高和颜色&…

react 页签(自行封装)

思路:封装一个页签组件,包裹页面组件,页面渲染之后把数据缓存到全局状态实现页面缓存。 浏览本博客之前先看一下我的博客实现的功能是否满足需求,实现功能: - 页面缓存 - 关闭当前页 - 鼠标右键>关闭当前 - 鼠标右…

Endnote文章编号从10开始

前部分章节已经写好,后续添加,endnote参考文献需要从特定序号如10开始 知乎回答 在word中点击Endnote,instant Formatting is on右下角有一个小箭头, 点开箭头后点击layout, 下边有一个Start with bibliography 里面输入要开始的…

Python中类的继承实现

""派生类继承了基类的一切",这里创建基类曲线,派生类有椭圆。派生类调用基类的方法,只需方法名前加上基类基类名作为前缀,再将派生类的self和其他参数传入。 当派生类与基类有同名的方法时,调用的是派…

按键+数码管

key.c #include "key.h" //把led.h文件包含进来 #include "system.h" //把timer0.h文件包含进来 #include "smg.h"extern uint num; char key_value; //有按键按下 char key_shourtflag;//没有按键按下uint KeyScan () //按键扫描函数 {…

Linux中关于head命令详解

head的作用 head用于查看文件的开头部分的内容。 head的参数 -q隐藏文件名-v 显示文件名-c<数目>显示的字节数-n<数目>显示的行数 head的案例 # 查看yum.log前五行内容 head -5 yum.log

vue2打包

首先&#xff0c;请确保您已经安装了Vue CLI。 打开终端或命令提示符&#xff0c;进入您的Vue项目的根目录。 运行以下命令来安装所需的依赖项&#xff1a; npm install安装完成后&#xff0c;运行以下命令来打包您的Vue项目&#xff1a; npm run build这将在您的项目根目录…

Cortex-M3/M4内核NVIC及HAL库函数详解(4):使用HAL库配置外部中断

0 工具准备 Keil uVision5 Cortex M3权威指南&#xff08;中文&#xff09; Cortex M3与M4权威指南 stm32f407的HAL库工程 STM32F4xx中文参考手册 1 使用HAL库配置外部中断 前面我们已经熟悉了有关内核部分的寄存器配置&#xff0c;接下来我们结合stm32f407的GPIO外设&#xf…

站长为什么都说WordPress太复杂不会用要放弃?

网络上经常看到有站长说要放弃WordPress&#xff0c;理由各有不同&#xff0c;比如有些说WordPress太复杂不会用&#xff1b;有些说WordPress是国外建站系统&#xff0c;在国内用来搭建访问速度太慢&#xff1b;也有些说WordPress是针对谷歌优化的&#xff0c;不适合国内的搜索…

UE 可靠UDP实现原理

发送 我们的消息发送都是通过 UChannel 来处理的&#xff0c;通过调用 UChannel::SendBunch 统一处理。 发送的 Bunch 是以 FOutBunch 的形式存在的。当 bReliable 为 True 的时候&#xff0c;表示 Bunch 是可靠的。 发送逻辑直接从UChannel::SendBunch处开始分析 1、大小限…

【算法与数据结构】1049、LeetCode 最后一块石头的重量 II

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题需要得到石头之间两两粉碎之后的最小值&#xff0c;那么一个简单的思路就是将这堆石头划分成大小相…

【MySQL】where和having的区别

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;数据库 ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 用途: 使用位置: 操作对象: 聚合函数: 示例&#xff1a; 结语 我的其他博客 前言 数据库中的 WHERE 和 HAVING 子句在 SQL 查…

线程池最佳实践!这几个坑使用不当绝对生产事故!!

拿来即用!这篇文章我会介绍我使用线程池的时候应该注意的坑以及一些优秀的实践。 1、正确声明线程池 线程池必须手动通过 ThreadPoolExecutor 的构造函数来声明&#xff0c;避免使用Executors 类创建线程池&#xff0c;会有 OOM 风险。 Executors 返回线程池对象的弊端如下(…

【机器学习300问】14、什么是特征工程?

当我学习到这个知识点的时候十分困惑&#xff0c;因为从名字中我完全无法理解这个什么东西。于是呢我就去问了一下维基百科&#xff0c;下面是他的回答&#xff1a; 特征工程&#xff08;英语&#xff1a;feature engineering&#xff09;又称特征提取&#xff08;英语&#xf…

H3C设备配置端口镜像案例

知识改变命运&#xff0c;技术就是要分享&#xff0c;有问题随时联系&#xff0c;免费答疑&#xff0c;欢迎联系&#xff01; 厦门微思网络​​​​​​ https://www.xmws.cn 华为认证\华为HCIA-Datacom\华为HCIP-Datacom\华为HCIE-Datacom Linux\RHCE\RHCE 9.0\RHCA\ Oracle O…

C语言练习day8

变种水仙花 变种水仙花_牛客题霸_牛客网 题目&#xff1a; 思路&#xff1a;我们拿到题目的第一步可以先看一看题目给的例子&#xff0c;1461这个数被从中间拆成了两部分&#xff1a;1和461&#xff0c;14和61&#xff0c;146和1&#xff0c;不知道看到这大家有没有觉得很熟…

NodeJs 第十八章 图片水印

图片处理是一个专业的事情。秉承着专业的事情就要交给专业的人处理。所以我们就要站在巨人的肩膀上去处理问题。 本章节主要介绍 jimp。jimp 是一个完全用JavaScript为Node编写的图像处理库&#xff0c;没有外部依赖。 jimp 支持图片类型 bmpgifjpegpngtiff 简单示例 本示例…

stm32f103c8r6 dma 测试

main.h文件 #include "stm32f10x.h" //STM32头文件 #include "sys.h" #include "delay.h" #include "usart.h" #include "dma.h" int main (void){//主程序 u8 i; //RCC_Configuration(); //时钟设置 uart_init…