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

Pythonpkg_resources模块动态加载插件实例分析

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

北京

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

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

看不清楚,换张图片

免费获取短信验证码

Pythonpkg_resources模块动态加载插件实例分析

使用标准库importlibimport_module()函数、django的import_string(),它们都可以动态加载指定的 Python 模块。

举两个动态加载例子:

举例一:

在你项目中有个test函数,位于your_project/demo/test.py中,那么你可以使用import_module来动态加载并调用这个函数而不需要在使用的地方通过import导入。

module_path = 'your_project/demo'
module = import_module(module_path)
module.test()

举例二:

django的中间件都用过吧,只需要在setting中配置好django就能自动被调用,这也是利用import_string动态加载的。

#settings.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
     ...
]
# 动态加载调用处代码
for middleware_path in reversed(settings.MIDDLEWARE):
    middleware = import_string(middleware_path)
    ...

以上方式会有一些缺点:

  • 所引用模块不存在时,在项目启动时不会及时抛出错误,只有在真正调用时才能被发现
  • 所引用模块要事先写好并放到指定位置,不能删
  • 半自动的可插拔性,想禁用某个插件功能需要手动修改代码。如想去掉django的SessionMiddleware功能,那需要手动去修改settings配置文件

pkg_resources实现动态加载插件

下面介绍另外一种动态 载插件的方法,与安装库setuptools一并安装的软件库pkg_resources,它基本解决了上述的问题,并且事实上成为了流行的插件实现方式。 pkg_resources操作的主要单位就是 Distribution(包分发),关于Distribution可以参考这里。Python 脚本启动时,pkg_resources识别出搜索路径中的所有 Distribution 的命名空间包,因此,我们会发现sys.path包含了很多pip安装的软件包的路径,并且可以正确执行import操作。

pkg_resources自带一个全局的WorkingSet对象,代表默认的搜索路径的工作集,也就是我们常用的sys.path工作集。有了这个工作集,那就能轻松实现动态导入任何模块了。

下面上案例:

这个案例是ansible-runner的一个事件处理插件,项目地址GitHub - ansible/ansible-runner-http。只需要把这个包安装到你的虚拟环境,ansible-runner就会自动识别并调用status_handler、event_handler两个事件处理函数。当卸载这个包后,ansible-runner就会使用默认的方式处理事件。相比前面介绍的import_module方式,这种动态加载方式好在对源代码侵入性少,实现真正的即插即用。下面分析它是怎么利用pkg_resources做到的。

ansible-runner-http项目源码目录结构:

├── README.md

├── ansible_runner_http

│├── __init__.py

│└── events.py

└── setup.py

event.py:

...
def status_handler(runner_config, data):
    plugin_config = get_configuration(runner_config)
    if plugin_config['runner_url'] is not None:
        status = send_request(plugin_config['runner_url'],
                              data=data,
                              headers=plugin_config['runner_headers'],
                              urlpath=plugin_config['runner_path'])
        logger.debug("POST Response {}".format(status))
    else:
        logger.info("HTTP Plugin Skipped")
def event_handler(runner_config, data):
    status_handler(runner_config, data)

__init__.py:

from .events import status_handler, event_handler # noqa

setup.py:

from setuptools import setup, find_packages
with open('README.md', 'r') as f:
    long_description = f.read()
setup(
    name="ansible-runner-http",
    version="1.0.0",
    author="Red Hat Ansible",
    url="https://github.com/ansible/ansible-runner-http",
    license='Apache',
    packages=find_packages(),
    long_description=long_description,
    long_description_content_type='text/markdown',
    install_requires=[
        'requests',
        'requests-unixsocket',
    ],
    #方式一:具体到某个module
    entry_points={'ansible_runner.plugins': ['http = ansible_runner_http']},
    #方式二:具体到某个module下的函数
    #entry_points={'ansible_runner.plugins': [
    #    'status_handler = ansible_runner_http:status_handler',
    #    'event_handler = ansible_runner_http:event_handler',
    #    ]
    #},
    zip_safe=False,
)

重点在setup中的entry_points选项:

  • 组名,以点号分隔便于组织层次,但与 Package 没有关联,如ansible_runner.plugin
  • 名字,如 http
  • Distribution 中的位置,可以指向一个module如ansible_runner_http。也可以指向module下某个函数如ansible_runner_http:status_handler,前面是 Module,后面是模块内的函数

这样一来一旦这个包被安装后,pkg_resources就可以动态识别这个插件了。

下面看调用方:

...
plugins = {
    #调用load方法,获取指向python的对象
    entry_point.name: entry_point.load()
    for entry_point
    #调用WorkingSet.iter_entry_points方法遍历所有EntryPoint,参数为组名
    in pkg_resources.iter_entry_points('ansible_runner.plugins')
}
...
def event_callback(self, event_data):
        '''
        Invoked for every Ansible event to collect stdout with the event data and store it for
        later use
        '''
    for plugin in plugins:
        plugins[plugin].event_handler(self.config, event_data)
        ...

方式一写法得到的plugins:

方式二写法得到的plugins:

到此这篇关于Python pkg_resources模块动态加载插件实例分析的文章就介绍到这了,更多相关Python 动态加载插件内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

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

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

Pythonpkg_resources模块动态加载插件实例分析

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

下载Word文档

猜你喜欢

Android动态加载资源实例解析

前不久跑去折腾高德 SDK 中的 HUD 功能,相信用过该功能的用户都知道 HUD 界面上的导航转向图标是动态变化的。从高德官方导航 javascript:;" onClick="javascript:tagshow(event, 'API
2022-06-06

Angular中模块和懒加载的示例分析

这篇文章主要介绍Angular中模块和懒加载的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、Angular 内置模块二、Angular 自定义模块当我们项目比较小的时候可以不用自定义模块。但是当我们项目非
2023-06-06

python中动态加载模块和类方法实现

python中动态加载模块和类方法实现测试代码 文件名: mytest.py 具体代码如下: 注意:模块名,类名,方法名都是变量。 #coding=UTF-8class TestClass: def sub(self,a,b):
2023-01-31

Spring Boot 如何热加载Jar实现动态插件?

本文主要介绍在 Spring Boot 工程中热加载 jar 包并注册成为 Bean 对象的一种实现思路,在动态扩展功能的同时支持在插件中注入主程序的 Bean 实现功能更强大的插件。

权限管理模块中动态加载Vue组件怎么实现

本篇内容介绍了“权限管理模块中动态加载Vue组件怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!登录状态保存当用户登录成功之后,需要将
2023-06-19

Spring Boot 如何热加载 jar 实现动态插件?

本文主要介绍在 Spring Boot 工程中热加载 jar 包并注册成为 Bean 对象的一种实现思路,在动态扩展功能的同时支持在插件中注入主程序的 Bean 实现功能更强大的插件。

node.js文件系统模块实例分析

这篇文章主要讲解了“node.js文件系统模块实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“node.js文件系统模块实例分析”吧!一、node.js文件系统模块node.jsjav
2023-06-30

编程热搜

  • 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动态编译

目录