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

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 abc

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

plugins/hello.py - 示例插件1

from plugin_base import PluginBase

class HelloPlugin(PluginBase):
    
    @classmethod
    def initialize(cls):
        print("HelloPlugin initialized")
        return cls()
        
    def execute(self, name="World"):
        print(f"Hello, {name}!")

plugins/goodbye.py - 示例插件2

from plugin_base import PluginBase

class GoodbyePlugin(PluginBase):
    
    @classmethod
    def 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 PluginBase

class 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] = obj
                        print(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.abstractmethod
    def initialize(cls, config=None):
        """支持传入配置"""
        pass

2.2 插件依赖管理

在插件类中添加:

class HelloPlugin(PluginBase):
    REQUIRED_PLUGINS = ['some_dependency']
    
    @classmethod
    def 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_packages

setup(
    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_points

class 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_class
            except 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"] = module
    spec.loader.exec_module(module)
    return module

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

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

# mini_plugin.py
import importlib
from pathlib import Path

class Plugin:
    def execute(self):
        raise NotImplementedError

class PluginManager:
    def __init__(self):
        self.plugins = {}
    
    def load_plugin(self, plugin_path):
        module_name = Path(plugin_path).stem
        spec = 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 None

if __name__ == "__main__":
    manager = PluginManager()
    plugin = manager.load_plugin("hello_plugin.py")  # 假设同级目录下有这个文件
    if plugin:
        plugin.execute()

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

from mini_plugin import Plugin

class HelloPlugin(Plugin):
    def execute(self):
        print("Hello from minimal plugin!")

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

相关文章:

  • JDK(Java Development Kit)从发布至今所有主要版本 的详细差异、新增特性及关键更新的总结,按时间顺序排列
  • 【架构师从入门到进阶】第五章:DNSCDN网关优化思路——第七节:网关-XSS攻击与预防
  • uniapp日常总结--uniapp页面跳转方式
  • 单片机Day05---静态数码管
  • Cocos Creator Shader入门实战(八):Shader实现圆形、椭圆、菱形等头像
  • IIC通信协议
  • Python快速入门指南:从零开始掌握Python编程
  • JetBrain/IDEA :Request for Open Source Development License
  • 基于springboot+vue的秦皇岛旅游景点管理系统
  • MySql 自我总结
  • GOC 指令集
  • 深入学习任何技术的实用指南
  • data_analysis14
  • C++之map,set的实现
  • AI大模型从0到1记录学习 day17
  • 基于论文的大模型应用:基于SmartETL的arXiv论文数据接入与预处理(二)
  • 5分钟搭建一个在线客服网站!免费!
  • Microsoft Office 如何启用和正常播放 Flash 控件
  • 腾讯后台开发 一面
  • vulkanscenegraph显示倾斜模型(5.8)-视景器编译
  • 如何设计网站建设引导页/百度收录查询
  • 江都住房和建设局网站/长尾关键词搜索网站
  • wordpress过FTP更新/石家庄百度快速排名优化
  • 南宁网站优化排名推广/怎么做app推广
  • 盘锦市建设局网站地址/网络舆情监测专业
  • 罗湖网站建设的公司哪家好/互联网广告代理可靠吗