Python?pluggy模塊的用法示例演示
1 pluggy 簡(jiǎn)介
- pluggy 作用:提供了一個(gè)簡(jiǎn)易便捷的插件系統(tǒng),可以做到插件與主題功能松耦合
- pluggy 是pytest,tox,devpi的核心框架
2 安裝
執(zhí)行如下命令即可
pip install pluggy
3 使用初體驗(yàn)
import pluggy # HookspecMarker 和 HookimplMarker 實(shí)質(zhì)上是一個(gè)裝飾器帶參數(shù)的裝飾器類,作用是給函數(shù)增加額外的屬性設(shè)置 hookspec = pluggy.HookspecMarker("myproject") hookimpl = pluggy.HookimplMarker("myproject") # 定義自己的Spec,這里可以理解為定義接口類 class MySpec: # hookspec 是一個(gè)裝飾類中的方法的裝飾器,為此方法增額外的屬性設(shè)置,這里myhook可以理解為定義了一個(gè)接口 @hookspec def myhook(self, arg1, arg2): pass # 定義了一個(gè)插件 class Plugin_1: # 插件中實(shí)現(xiàn)了上面定義的接口,同樣這個(gè)實(shí)現(xiàn)接口的方法用 hookimpl裝飾器裝飾,功能是返回兩個(gè)參數(shù)的和 @hookimpl def myhook(self, arg1, arg2): print("inside Plugin_1.myhook()") return arg1 + arg2 # 定義第二個(gè)插件 class Plugin_2: # 插件中實(shí)現(xiàn)了上面定義的接口,同樣這個(gè)實(shí)現(xiàn)接口的方法用 hookimpl裝飾器裝飾,功能是返回兩個(gè)參數(shù)的差 @hookimpl def myhook(self, arg1, arg2): print("inside Plugin_2.myhook()") return arg1 - arg2 # 實(shí)例化一個(gè)插件管理的對(duì)象,注意這里的名稱要與文件開頭定義裝飾器的時(shí)候的名稱一致 pm = pluggy.PluginManager("myproject") # 將自定義的接口類加到鉤子定義中去 pm.add_hookspecs(MySpec) # 注冊(cè)定義的兩個(gè)插件 pm.register(Plugin_1()) pm.register(Plugin_2()) # 通過插件管理對(duì)象的鉤子調(diào)用方法,這時(shí)候兩個(gè)插件中的這個(gè)方法都會(huì)執(zhí)行,而且遵循后注冊(cè)先執(zhí)行即LIFO的原則,兩個(gè)插件的結(jié)果講義列表的形式返回 results = pm.hook.myhook(arg1=1, arg2=2) print(results)
執(zhí)行結(jié)果如下:
inside Plugin_2.myhook()
inside Plugin_1.myhook()
[-1, 3]
4 詳解解釋
從代碼上看比較繞,其實(shí)通俗一點(diǎn)理解,其實(shí)挺簡(jiǎn)單的,可以理解為首先定義一個(gè)接口類,然后定義很多插件類,插件類想要多少就定義多少, 接口類中要定義接口,上面的例子值定義了一個(gè)接口,其實(shí)可以定義很多接口,在每個(gè)插件類中需要選擇接口類中的接口去實(shí)現(xiàn),當(dāng)然也不需要每個(gè) 都需要去實(shí)現(xiàn),可以根據(jù)自己的需要有選擇的去實(shí)現(xiàn)。
舉個(gè)例子:
比如定義了一個(gè)接口類,接口類中定義了10個(gè)接口,同時(shí)定義了3個(gè)類,這三個(gè)類分別實(shí)現(xiàn)了接口類中3個(gè)接口,6個(gè)接口和10個(gè)接口,然后實(shí)例化一個(gè)插件管理的對(duì)象,實(shí)例化對(duì)象將接口類加入定義模板中,然后去注冊(cè)這三個(gè)類,注冊(cè)之后,就可以通過插件管理對(duì)象的鉤子去調(diào)用接口類中的每個(gè)方法了,比如調(diào)用頭三個(gè)方法,因?yàn)槊總€(gè)插件中都實(shí)現(xiàn)了,所以就會(huì)有三個(gè)結(jié)果,調(diào)用后面4-6的接口時(shí),因?yàn)橹挥袃蓚€(gè)插件實(shí)現(xiàn)了,所以只會(huì)有兩個(gè)結(jié)果返回,調(diào)用7-10的接口因?yàn)橹挥幸粋€(gè)插件類實(shí)現(xiàn)了,所以就會(huì)只有一個(gè)結(jié)果返回,這樣插件使用起來就非常靈活,可以真正做到“熱插拔”
下面用代碼示例演示:
import pluggy # HookspecMarker 和 HookimplMarker 實(shí)質(zhì)上是一個(gè)裝飾器帶參數(shù)的裝飾器類,作用是給函數(shù)增加額外的屬性設(shè)置 hookspec = pluggy.HookspecMarker("myproject") hookimpl = pluggy.HookimplMarker("myproject") # 定義自己的Spec,這里可以理解為定義接口類 class MySpec: # hookspec 是一個(gè)裝飾類中的方法的裝飾器,為此方法增額外的屬性設(shè)置,這里myhook可以理解為定義了3個(gè)接口 @hookspec def myhook1(self, arg1, arg2): pass @hookspec def myhook2(self, arg1, arg2): pass @hookspec def myhook3(self, arg1, arg2): pass # 定義了一個(gè)插件 class Plugin_1: # 插件中實(shí)現(xiàn)了上面定義的接口,同樣這個(gè)實(shí)現(xiàn)接口的方法用 hookimpl裝飾器裝飾,功能是返回兩個(gè)參數(shù)的和 @hookimpl def myhook1(self, arg1, arg2): print("inside Plugin_1.myhook1()") return arg1 + arg2 @hookimpl def myhook2(self, arg1, arg2): print("inside Plugin_1.myhook2()") return arg1 + arg2 +1 @hookimpl def myhook4(self, arg1, arg2): print("inside Plugin_1.myhook4()") return arg1 + arg2 + 2 # 定義第二個(gè)插件 class Plugin_2: # 插件中實(shí)現(xiàn)了上面定義的接口,同樣這個(gè)實(shí)現(xiàn)接口的方法用 hookimpl裝飾器裝飾,功能是返回兩個(gè)參數(shù)的差 @hookimpl def myhook1(self, arg1, arg2): print("inside Plugin_2.myhook1()") return arg1 - arg2 @hookimpl def myhook2(self, arg1, arg2): print("inside Plugin_2.myhook2()") return arg1 - arg2 -1 @hookimpl def myhook3(self, arg1, arg2): print("inside Plugin_2.myhook3()") return arg1 - arg2 -2 # 實(shí)例化一個(gè)插件管理的對(duì)象,注意這里的名稱要與文件開頭定義裝飾器的時(shí)候的名稱一致 pm = pluggy.PluginManager("myproject") # 將自定義的接口類加到鉤子定義中去 pm.add_hookspecs(MySpec) # 注冊(cè)定義的兩個(gè)插件 pm.register(Plugin_1()) pm.register(Plugin_2()) # 通過插件管理對(duì)象的鉤子調(diào)用方法,這時(shí)候兩個(gè)插件中的這個(gè)方法都會(huì)執(zhí)行,而且遵循后注冊(cè)先執(zhí)行即LIFO的原則,兩個(gè)插件的結(jié)果講義列表的形式返回 results = pm.hook.myhook1(arg1=1, arg2=2) print(results) results = pm.hook.myhook2(arg1=1, arg2=2) print(results) results = pm.hook.myhook3(arg1=1, arg2=2) print(results) results = pm.hook.myhook4(arg1=1, arg2=2) print(results)
執(zhí)行結(jié)果如下:
inside Plugin_2.myhook1()
inside Plugin_1.myhook1()
[-1, 3]
inside Plugin_2.myhook2()
inside Plugin_1.myhook2()
[-2, 4]
inside Plugin_2.myhook3()
[-3]
inside Plugin_1.myhook4()
[5]
從上面的代碼示例可以看出:
- 1)myhook1 和 myhook2 因?yàn)閮蓚€(gè)插件都實(shí)現(xiàn)了,所有返回兩個(gè)結(jié)果,而且是倒序的
- 2)myhook3 因?yàn)橹挥胁寮?實(shí)現(xiàn)了,所以只有一個(gè)返回結(jié)果
- 3)myhook4 在spec中未定義,這里卻也有結(jié)果,目前理解可能是pluggy的bug,待后續(xù)看源碼后解釋
5 HookspeckMarker裝飾器支持傳入一些特定的參數(shù)
當(dāng)傳入firstresult=True時(shí),獲取第一個(gè)plugin執(zhí)行結(jié)果后就停止繼續(xù)執(zhí)行
import pluggy # HookspecMarker 和 HookimplMarker 實(shí)質(zhì)上是一個(gè)裝飾器帶參數(shù)的裝飾器類,作用是給函數(shù)增加額外的屬性設(shè)置 hookspec = pluggy.HookspecMarker("myproject") hookimpl = pluggy.HookimplMarker("myproject") # 定義自己的Spec,這里可以理解為定義接口類 class MySpec: # hookspec 是一個(gè)裝飾類中的方法的裝飾器,為此方法增額外的屬性設(shè)置,這里myhook可以理解為定義了一個(gè)接口 @hookspec(firstresult=True) def myhook(self, arg1, arg2): pass # 定義了一個(gè)插件 class Plugin_1: # 插件中實(shí)現(xiàn)了上面定義的接口,同樣這個(gè)實(shí)現(xiàn)接口的方法用 hookimpl裝飾器裝飾,功能是返回兩個(gè)參數(shù)的和 @hookimpl def myhook(self, arg1, arg2): print("inside Plugin_1.myhook()") return arg1 + arg2 # 定義第二個(gè)插件 class Plugin_2: # 插件中實(shí)現(xiàn)了上面定義的接口,同樣這個(gè)實(shí)現(xiàn)接口的方法用 hookimpl裝飾器裝飾,功能是返回兩個(gè)參數(shù)的差 @hookimpl def myhook(self, arg1, arg2): print("inside Plugin_2.myhook()") return arg1 - arg2 # 實(shí)例化一個(gè)插件管理的對(duì)象,注意這里的名稱要與文件開頭定義裝飾器的時(shí)候的名稱一致 pm = pluggy.PluginManager("myproject") # 將自定義的接口類加到鉤子定義中去 pm.add_hookspecs(MySpec) # 注冊(cè)定義的兩個(gè)插件 pm.register(Plugin_1()) pm.register(Plugin_2()) # 通過插件管理對(duì)象的鉤子調(diào)用方法,這時(shí)候兩個(gè)插件中的這個(gè)方法都會(huì)執(zhí)行,而且遵循后注冊(cè)先執(zhí)行即LIFO的原則,兩個(gè)插件的結(jié)果講義列表的形式返回 results = pm.hook.myhook(arg1=1, arg2=2) print(results)
執(zhí)行結(jié)果如下:
inside Plugin_2.myhook()
-1
6 HookImplMarker裝飾器也支持傳入一些特定的參數(shù)
常用的有tryfirst和trylast以及hookwrapper
- 當(dāng)傳入tryfirst=True時(shí),表示這個(gè)類的hook函數(shù)會(huì)優(yōu)先執(zhí)行,其他的仍然按照后進(jìn)先出的順序執(zhí)行
import pluggy # HookspecMarker 和 HookimplMarker 實(shí)質(zhì)上是一個(gè)裝飾器帶參數(shù)的裝飾器類,作用是給函數(shù)增加額外的屬性設(shè)置 hookspec = pluggy.HookspecMarker("myproject") hookimpl = pluggy.HookimplMarker("myproject") # 定義自己的Spec,這里可以理解為定義接口類 class MySpec: # hookspec 是一個(gè)裝飾類中的方法的裝飾器,為此方法增額外的屬性設(shè)置,這里myhook可以理解為定義了一個(gè)接口 @hookspec def myhook(self, arg1, arg2): pass # 定義了一個(gè)插件 class Plugin_1: # 插件中實(shí)現(xiàn)了上面定義的接口,同樣這個(gè)實(shí)現(xiàn)接口的方法用 hookimpl裝飾器裝飾,功能是返回兩個(gè)參數(shù)的和 @hookimpl(tryfirst=True) def myhook(self, arg1, arg2): print("inside Plugin_1.myhook()") return arg1 + arg2 # 定義第二個(gè)插件 class Plugin_2: # 插件中實(shí)現(xiàn)了上面定義的接口,同樣這個(gè)實(shí)現(xiàn)接口的方法用 hookimpl裝飾器裝飾,功能是返回兩個(gè)參數(shù)的差 @hookimpl def myhook(self, arg1, arg2): print("inside Plugin_2.myhook()") return arg1 - arg2 # 定義第三個(gè)插件 class Plugin_3: # 插件中實(shí)現(xiàn)了上面定義的接口,同樣這個(gè)實(shí)現(xiàn)接口的方法用 hookimpl裝飾器裝飾,功能是返回兩個(gè)參數(shù)的差 @hookimpl def myhook(self, arg1, arg2): print("inside Plugin_3.myhook()") return arg1 - arg2+10 # 實(shí)例化一個(gè)插件管理的對(duì)象,注意這里的名稱要與文件開頭定義裝飾器的時(shí)候的名稱一致 pm = pluggy.PluginManager("myproject") # 將自定義的接口類加到鉤子定義中去 pm.add_hookspecs(MySpec) # 注冊(cè)定義的兩個(gè)插件 pm.register(Plugin_1()) pm.register(Plugin_2()) pm.register(Plugin_3()) # 通過插件管理對(duì)象的鉤子調(diào)用方法,這時(shí)候兩個(gè)插件中的這個(gè)方法都會(huì)執(zhí)行,而且遵循后注冊(cè)先執(zhí)行即LIFO的原則,兩個(gè)插件的結(jié)果講義列表的形式返回 results = pm.hook.myhook(arg1=1, arg2=2) print(results)
執(zhí)行結(jié)果讓如下:
inside Plugin_1.myhook()
inside Plugin_3.myhook()
inside Plugin_2.myhook()
[3, 9, -1]
- 當(dāng)傳入trylast=True,表示當(dāng)前插件的hook函數(shù)會(huì)盡可能晚的執(zhí)行,其他的仍然按照后進(jìn)先出的順序執(zhí)行
import pluggy # HookspecMarker 和 HookimplMarker 實(shí)質(zhì)上是一個(gè)裝飾器帶參數(shù)的裝飾器類,作用是給函數(shù)增加額外的屬性設(shè)置 hookspec = pluggy.HookspecMarker("myproject") hookimpl = pluggy.HookimplMarker("myproject") # 定義自己的Spec,這里可以理解為定義接口類 class MySpec: # hookspec 是一個(gè)裝飾類中的方法的裝飾器,為此方法增額外的屬性設(shè)置,這里myhook可以理解為定義了一個(gè)接口 @hookspec def myhook(self, arg1, arg2): pass # 定義了一個(gè)插件 class Plugin_1: # 插件中實(shí)現(xiàn)了上面定義的接口,同樣這個(gè)實(shí)現(xiàn)接口的方法用 hookimpl裝飾器裝飾,功能是返回兩個(gè)參數(shù)的和 @hookimpl() def myhook(self, arg1, arg2): print("inside Plugin_1.myhook()") return arg1 + arg2 # 定義第二個(gè)插件 class Plugin_2: # 插件中實(shí)現(xiàn)了上面定義的接口,同樣這個(gè)實(shí)現(xiàn)接口的方法用 hookimpl裝飾器裝飾,功能是返回兩個(gè)參數(shù)的差 @hookimpl(trylast=True) def myhook(self, arg1, arg2): print("inside Plugin_2.myhook()") return arg1 - arg2 # 定義第三個(gè)插件 class Plugin_3: # 插件中實(shí)現(xiàn)了上面定義的接口,同樣這個(gè)實(shí)現(xiàn)接口的方法用 hookimpl裝飾器裝飾,功能是返回兩個(gè)參數(shù)的差 @hookimpl def myhook(self, arg1, arg2): print("inside Plugin_3.myhook()") return arg1 - arg2+10 # 實(shí)例化一個(gè)插件管理的對(duì)象,注意這里的名稱要與文件開頭定義裝飾器的時(shí)候的名稱一致 pm = pluggy.PluginManager("myproject") # 將自定義的接口類加到鉤子定義中去 pm.add_hookspecs(MySpec) # 注冊(cè)定義的兩個(gè)插件 pm.register(Plugin_1()) pm.register(Plugin_2()) pm.register(Plugin_3()) # 通過插件管理對(duì)象的鉤子調(diào)用方法,這時(shí)候兩個(gè)插件中的這個(gè)方法都會(huì)執(zhí)行,而且遵循后注冊(cè)先執(zhí)行即LIFO的原則,兩個(gè)插件的結(jié)果講義列表的形式返回 results = pm.hook.myhook(arg1=1, arg2=2) print(results)
執(zhí)行結(jié)果如下:
inside Plugin_3.myhook()
inside Plugin_1.myhook()
inside Plugin_2.myhook()
[9, 3, -1]
- 當(dāng)傳入hookwrapper=True時(shí),需要在這個(gè)plugin中實(shí)現(xiàn)一個(gè)yield,plugin先執(zhí)行yield
之前的代碼,然后去執(zhí)行其他的pluggin,然后再回來執(zhí)行yield之后的代碼,同時(shí)通過yield可以 獲取到其他插件執(zhí)行的結(jié)果
import pluggy # HookspecMarker 和 HookimplMarker 實(shí)質(zhì)上是一個(gè)裝飾器帶參數(shù)的裝飾器類,作用是給函數(shù)增加額外的屬性設(shè)置 hookspec = pluggy.HookspecMarker("myproject") hookimpl = pluggy.HookimplMarker("myproject") # 定義自己的Spec,這里可以理解為定義接口類 class MySpec: # hookspec 是一個(gè)裝飾類中的方法的裝飾器,為此方法增額外的屬性設(shè)置,這里myhook可以理解為定義了一個(gè)接口 @hookspec def myhook(self, arg1, arg2): pass # 定義了一個(gè)插件 class Plugin_1: # 插件中實(shí)現(xiàn)了上面定義的接口,同樣這個(gè)實(shí)現(xiàn)接口的方法用 hookimpl裝飾器裝飾,功能是返回兩個(gè)參數(shù)的和 @hookimpl() def myhook(self, arg1, arg2): print("inside Plugin_1.myhook()") return arg1 + arg2 # 定義第二個(gè)插件 class Plugin_2: # 插件中實(shí)現(xiàn)了上面定義的接口,同樣這個(gè)實(shí)現(xiàn)接口的方法用 hookimpl裝飾器裝飾,功能是返回兩個(gè)參數(shù)的差 @hookimpl(hookwrapper=True) def myhook(self, arg1, arg2): print("inside Plugin_2.myhook() before yield...") output=yield result=output.get_result() print(result) print("inside Plugin_2.myhook() after yield...") # 定義第三個(gè)插件 class Plugin_3: # 插件中實(shí)現(xiàn)了上面定義的接口,同樣這個(gè)實(shí)現(xiàn)接口的方法用 hookimpl裝飾器裝飾,功能是返回兩個(gè)參數(shù)的差 @hookimpl def myhook(self, arg1, arg2): print("inside Plugin_3.myhook()") return arg1 - arg2+10 # 實(shí)例化一個(gè)插件管理的對(duì)象,注意這里的名稱要與文件開頭定義裝飾器的時(shí)候的名稱一致 pm = pluggy.PluginManager("myproject") # 將自定義的接口類加到鉤子定義中去 pm.add_hookspecs(MySpec) # 注冊(cè)定義的兩個(gè)插件 pm.register(Plugin_1()) pm.register(Plugin_2()) pm.register(Plugin_3()) # 通過插件管理對(duì)象的鉤子調(diào)用方法,這時(shí)候兩個(gè)插件中的這個(gè)方法都會(huì)執(zhí)行,而且遵循后注冊(cè)先執(zhí)行即LIFO的原則,兩個(gè)插件的結(jié)果講義列表的形式返回 results = pm.hook.myhook(arg1=1, arg2=2) print(results)
執(zhí)行結(jié)果如下:
inside Plugin_2.myhook() before yield...
inside Plugin_3.myhook()
inside Plugin_1.myhook()
[9, 3]
inside Plugin_2.myhook() after yield...
[9, 3]
到此這篇關(guān)于Python pluggy模塊的用法的文章就介紹到這了,更多相關(guān)Python pluggy模塊內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python連接access數(shù)據(jù)庫(kù)兩種方式總結(jié)
這篇文章主要介紹了python連接access數(shù)據(jù)庫(kù)兩種方式的相關(guān)資料,SQLAlchemy使用access方言進(jìn)行連接,而pyodbc則通過pyodbc模塊實(shí)現(xiàn)連接,文章還提供了連接代碼示例,需要的朋友可以參考下2025-02-02使用Python編程分析火爆全網(wǎng)的魷魚游戲豆瓣影評(píng)
本文來為大家介紹如何使用Python爬取影評(píng)的操作,主要是爬取《魷魚游戲》在豆瓣上的一些影評(píng),對(duì)數(shù)據(jù)做一些簡(jiǎn)單的分析,用數(shù)據(jù)的角度重新審視下這部劇,有需要的朋友可以借鑒參考下2021-10-10Python利用xmltodict實(shí)現(xiàn)字典和xml互相轉(zhuǎn)換的示例代碼
xmltodict是一個(gè)Python第三方庫(kù),用于處理XML數(shù)據(jù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-12-12Python Matplotlib 實(shí)現(xiàn)3D繪圖詳解
Matplotlib在二維繪圖的基礎(chǔ)上,構(gòu)建了一部分較為實(shí)用的3D繪圖程序包。本文將為大家詳細(xì)介紹通過調(diào)用該程序包接口繪制 3D散點(diǎn)圖、3D曲面圖、3D線框圖。感興趣的同學(xué)可以了解一下2021-11-11python的pygal模塊繪制反正切函數(shù)圖像方法
在本篇文章中我們給大家整理了關(guān)于如何用python的pygal模塊繪制反正切函數(shù)圖像的知識(shí)點(diǎn)內(nèi)容,有需要的朋友們可以學(xué)習(xí)下。2019-07-07python爬蟲實(shí)現(xiàn)爬取同一個(gè)網(wǎng)站的多頁(yè)數(shù)據(jù)的實(shí)例講解
在本篇文章里小編給大家整理了一篇關(guān)于python爬蟲實(shí)現(xiàn)爬取同一個(gè)網(wǎng)站的多頁(yè)數(shù)據(jù)的實(shí)例內(nèi)容,有興趣的朋友們可以學(xué)習(xí)參考下。2021-01-01Python自然語言處理使用spaCy庫(kù)進(jìn)行文本預(yù)處理
這篇文章主要為大家介紹了Python自然語言處理使用spaCy庫(kù)進(jìn)行文本預(yù)處理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05