欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python pkg_resources模塊動態(tài)加載插件實例分析

 更新時間:2022年08月04日 10:22:04   作者:藍綠色~菠菜  
當編寫應用軟件時,我們通常希望程序具有一定的擴展性,額外的功能——甚至所有非核心的功能,都能通過插件實現,具有可插拔性。特別是使用 Python 編寫的程序,由于語言本身的動態(tài)特性,為我們的插件方案提供了很多種實現方式

使用標準庫importlibimport_module()函數、django的import_string(),它們都可以動態(tài)加載指定的 Python 模塊。

舉兩個動態(tài)加載例子:

舉例一:

在你項目中有個test函數,位于your_project/demo/test.py中,那么你可以使用import_module來動態(tài)加載并調用這個函數而不需要在使用的地方通過import導入。

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

舉例二:

django的中間件都用過吧,只需要在setting中配置好django就能自動被調用,這也是利用import_string動態(tài)加載的。

#settings.py
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
     ...
]
# 動態(tài)加載調用處代碼
for middleware_path in reversed(settings.MIDDLEWARE):
    middleware = import_string(middleware_path)
    ...

以上方式會有一些缺點:

  • 所引用模塊不存在時,在項目啟動時不會及時拋出錯誤,只有在真正調用時才能被發(fā)現
  • 所引用模塊要事先寫好并放到指定位置,不能刪
  • 半自動的可插拔性,想禁用某個插件功能需要手動修改代碼。如想去掉django的SessionMiddleware功能,那需要手動去修改settings配置文件

pkg_resources實現動態(tài)加載插件

下面介紹另外一種動態(tài) 載插件的方法,與安裝庫setuptools一并安裝的軟件庫pkg_resources,它基本解決了上述的問題,并且事實上成為了流行的插件實現方式。 pkg_resources操作的主要單位就是 Distribution(包分發(fā)),關于Distribution可以參考這里。Python 腳本啟動時,pkg_resources識別出搜索路徑中的所有 Distribution 的命名空間包,因此,我們會發(fā)現sys.path包含了很多pip安裝的軟件包的路徑,并且可以正確執(zhí)行import操作。

pkg_resources自帶一個全局的WorkingSet對象,代表默認的搜索路徑的工作集,也就是我們常用的sys.path工作集。有了這個工作集,那就能輕松實現動態(tài)導入任何模塊了。

下面上案例:

這個案例是ansible-runner的一個事件處理插件,項目地址GitHub - ansible/ansible-runner-http。只需要把這個包安裝到你的虛擬環(huán)境,ansible-runner就會自動識別并調用status_handler、event_handler兩個事件處理函數。當卸載這個包后,ansible-runner就會使用默認的方式處理事件。相比前面介紹的import_module方式,這種動態(tài)加載方式好在對源代碼侵入性少,實現真正的即插即用。下面分析它是怎么利用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就可以動態(tài)識別這個插件了。

下面看調用方:

...
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模塊動態(tài)加載插件實例分析的文章就介紹到這了,更多相關Python 動態(tài)加載插件內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Python基于生成器迭代實現的八皇后問題示例

    Python基于生成器迭代實現的八皇后問題示例

    這篇文章主要介紹了Python基于生成器迭代實現的八皇后問題,簡單描述了八皇后問題,并結合實例形式分析了Python基于生成器迭代解決八皇后問題的相關操作技巧,需要的朋友可以參考下
    2018-05-05
  • python類的繼承實例詳解

    python類的繼承實例詳解

    這篇文章主要介紹了python類的繼承實例詳解的相關資料,需要的朋友可以參考下
    2017-03-03
  • Python操作Word批量生成合同的實現示例

    Python操作Word批量生成合同的實現示例

    這篇文章主要介紹了Python操作Word批量生成合同的實現示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-08-08
  • python 如何用 Hypothesis 來自動化單元測試

    python 如何用 Hypothesis 來自動化單元測試

    這篇文章主要介紹了python 如何用 Hypothesis 來自動化單元測試,幫助大家更好的理解和學習使用python,感興趣的朋友可以了解下
    2021-03-03
  • python中decimal模塊的具體使用

    python中decimal模塊的具體使用

    本文主要介紹了python中decimal模塊的具體使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-01-01
  • 如何用定值 Cookie 實現反爬詳解

    如何用定值 Cookie 實現反爬詳解

    這篇文章主要為大家介紹了如何用定值 Cookie 實現反爬示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04
  • Python筆記之代理模式

    Python筆記之代理模式

    這篇文章主要為大家詳細介紹了Python筆記之代理模式,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • python列表的增刪改查實例代碼

    python列表的增刪改查實例代碼

    下面小編就為大家分享一篇python列表的增刪改查實例代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-01-01
  • python實現定時壓縮指定文件夾發(fā)送郵件

    python實現定時壓縮指定文件夾發(fā)送郵件

    這篇文章主要為大家詳細介紹了python實現定時壓縮指定文件夾發(fā)送郵件,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-04-04
  • Matplotlib繪圖基礎之坐標軸詳解

    Matplotlib繪圖基礎之坐標軸詳解

    Matplotlib的坐標軸是用于在繪圖中表示數據的位置的工具,也是為了幫助觀察者了解圖像中數據的位置和大小,下面小編就來和大家詳細聊聊Matplotlib繪圖時坐標軸的具體使用吧
    2023-07-07

最新評論