網站首頁 編程語言 正文
使用標準庫importlib
的import_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:
原文鏈接:https://blog.csdn.net/bocai_xiaodaidai/article/details/125971394
相關推薦
- 2022-02-22 解決:DevTools failed to load SourceMap:... net::ERR_
- 2022-03-16 C#語言主要語言區域_C#教程
- 2023-05-22 shell腳本自動輸入用戶名和密碼的實現_linux shell
- 2022-07-03 C#中的委托Delegate_C#教程
- 2022-07-31 Android?中的類文件和類加載器詳情_Android
- 2022-05-22 Virtualbox?安裝?docker的流程分析_VirtualBox
- 2022-04-19 C#多線程系列之線程的創建和生命周期_C#教程
- 2022-11-12 python?鏡像環境搭建總結_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支