⑴ 如何在python實現程序載入插件(動態載入模塊文件,插件化開發)
在Python中實現程序載入插件(動態載入模塊文件,插件化開發)
動態載入插件是許多軟體,如pycharm,Minecraft,泰拉瑞亞,飢荒,vim,vscode的常見功能,讓它們能夠拓展軟體本身功能。Python模塊的格式為.py(或.pyd),這為動態載入提供了便利。
實現動態導入模塊,通常有兩種方式:使用import關鍵字和使用__import__函數,但它們都存在限制。import關鍵字載入的模塊名必須確定,且使用pyinstaller或nuke打包時不允許模塊名為空。而使用__import__函數雖官方不推薦,但它是一種實現方式。
推薦使用importlib模塊,它是import的實現,功能強大且使用簡單,通過importlib.import_mole參數可以指定包和模塊。使用相對路徑導入時需注意exe文件的位置。動態導入上層模塊時,可以通過修改sys.path列表來添加搜索路徑,使用'..'或絕對路徑。
動態尋找插件時,可以使用os.path或pathlib模塊來管理文件。實現流程包括掃描指定插件文件夾下的所有文件和文件夾,過濾出所需文件,然後將文件轉換為可以傳入importlib.import_mole()參數的形式。
示例:實現掃描並導入插件文件夾中的插件文件。此操作可以在主程序文件中執行,例如在__main__1.py或__main__2.py文件中,實現掃描指定文件夾並導入文件夾中的插件。在項目中,可參考hpyculator/calculate_manager.py實現動態載入插件。
具有插件載入功能的庫/軟體包括:Fallen-Breath/MCDReforged、nonebot/nonebot2、HowieHz/hpyculator等。寫文章初次嘗試,歡迎各位大佬提出寶貴意見。
⑵ python怎麼調用c的動態鏈接庫
Python調用C/C++動態鏈接庫的需求
在自動化測試過程中,難免會遇到語言混合使用的情況,這不,我們也遇到了。初步決定採用Robot Framework作為自動化測試框架後,其支持Java和Python,而Python作為主流的語言,怎麼能放棄使用它的機會^_^。 然而產品採用是古老90年代開發的C/S結構,因為古老,當時也沒有考慮到對產品的測試進行自動化,Client端並沒有預留CLI(Command Line interface)形式的介面,真是雪上加霜啊。
那怎麼自動化?採用AutoIT來對客戶端界面進行自動化測試?可惜AutoIT對當初開發採用的控制項識別不是很好,如果採用控制項所在位置來進行控制的方式,又會導致自動化測試並不是很穩定。那麼!!!只有自己開發介面了,目前在Client端開發出CLI形式的介面,將其封裝為DLL,然後在Robot FrameWork框架中採用Python對DLL進行調用。任務艱巨哪!
Python調用DLL例子
示例一
首先,在創建一個DLL工程(本人是在VS 2005中創建),頭文件:
[cpp] view plain 在CODE上查看代碼片派生到我的代碼片//hello.h
#ifdef EXPORT_HELLO_DLL
#define HELLO_API __declspec(dllexport)
#else
#define HELLO_API __declspec(dllimport)
#endif
extern "C"
{
HELLO_API int IntAdd(int , int);
}
CPP文件:
[cpp] view plain 在CODE上查看代碼片派生到我的代碼片//hello.cpp
#define EXPORT_HELLO_DLL
#include "hello.h"
HELLO_API int IntAdd(int a, int b)
{
return a + b;
}
這里有兩個注意點:
(1)弄清楚編譯的時候函數的調用約定採用的__cdecl還是__stdcall,因為根據DLL中函數調用約定方式,Python將使用相應的函數載入DLL。
(2)如果採用C++的工程,那麼導出的介面需要extern "C",這樣python中才能識別導出的函數。
我的工程中採用__cdecl函數調用約定方式進行編譯鏈接產生hello.dll,然後Python中採用ctypes庫對hello.dll進行載入和函數調用:
[python] view plain 在CODE上查看代碼片派生到我的代碼片from ctypes import *
dll = cdll.LoadLibrary('hello.dll');
ret = dll.IntAdd(2, 4);
print ret;
OK,一個小例子已經完成了,如果你感興趣,但還沒試過,那就嘗試一下吧。
示例二
示例一隻是一個"hello world"級別的程序,實際運用中更多的需要傳遞數據結構、字元串等,才能滿足我們的需求。那麼這個示例將展示,如何傳遞數據結構參數,以及如何通過數據結構獲取返回值。
首先編寫DLL工程中的頭文件:
[cpp] view plain 在CODE上查看代碼片派生到我的代碼片//hello.h
#ifdef EXPORT_HELLO_DLL
#define HELLO_API __declspec(dllexport)
#else
#define HELLO_API __declspec(dllimport)
#endif
#define ARRAY_NUMBER 20
#define STR_LEN 20
struct StructTest
{
int number;
char* pChar;
char str[STR_LEN];
int iArray[ARRAY_NUMBER];
};
extern "C"
{
//HELLO_API int IntAdd(int , int);
HELLO_API char* GetStructInfo(struct StructTest* pStruct);}
CPP文件如下:
[cpp] view plain 在CODE上查看代碼片派生到我的代碼片//hello.cpp
#include <string.h>
#define EXPORT_HELLO_DLL
#include "hello.h"
HELLO_API char* GetStructInfo(struct StructTest* pStruct){
for (int i = 0; i < ARRAY_NUMBER; i++)
pStruct->iArray[i] = i;
pStruct->pChar = "hello python!";
strcpy (pStruct->str, "hello world!");
pStruct->number = 100;
return "just OK";
}
GetStructInfo這個函數通過傳遞一個StructTest類型的指針,然後對對象中的屬性進行賦值,最後返回"just OK".
編寫Python調用代碼如下,首先在Python中繼承Structure構造一個和C DLL中一致的數據結構StructTest,然後設置函數GetStructInfo的參數類型和返回值類型,最後創建一個StructTest對象,並將其轉化為指針作為參數,調用函數GetStrcutInfo,最後通過輸出數據結構的值來檢查是否調用成功:
[python] view plain 在CODE上查看代碼片派生到我的代碼片from ctypes import *
ARRAY_NUMBER = 20;
STR_LEN = 20;
#define type
INTARRAY20 = c_int * ARRAY_NUMBER;
CHARARRAY20 = c_char * STR_LEN;
#define struct
class StructTest(Structure):
_fields_ = [
("number", c_int),
("pChar", c_char_p),
("str", CHARARRAY20),
("iArray", INTARRAY20)
]
#load dll and get the function object
dll = cdll.LoadLibrary('hello.dll');
GetStructInfo = dll.GetStructInfo;
#set the return type
GetStructInfo.restype = c_char_p;
#set the argtypes
GetStructInfo.argtypes = [POINTER(StructTest)];objectStruct = StructTest();
#invoke api GetStructInfo
retStr = GetStructInfo(byref(objectStruct));#check result
print "number: ", objectStruct.number;
print "pChar: ", objectStruct.pChar;
print "str: ", objectStruct.str;
for i,val in enumerate(objectStruct.iArray):
print 'Array[i]: ', val;
print retStr;
總結
1. 用64位的Python去載入32位的DLL會出錯
2. 以上只是些測試程序,在編寫Python過程中盡可能的使用"try Except"來處理異常3. 注意在Python與C DLL交互的時候位元組對齊問題4. ctypes庫的功能還有待繼續探索
⑶ python調用dll找不到模塊
在Python中調用DLL(動態鏈接庫)時遇到「找不到模塊」的錯誤通常是由於幾種常見原因引起的。這些問題可能涉及到路徑問題、依賴問題、位數不匹配
原因和解決策略:
1. 路徑問題:如果DLL文件不在程序的搜索路徑中,Python就無法找到它。確保DLL路徑被正確添加到系統路徑,或者通過代碼指定路徑。
2. 依賴問題:DLL可能依賴於其他庫,如果這些庫沒有被正確安裝或者沒有放在正確的路徑中,就會導致載入失敗。使用工具如Dependency Walker (適用於Windows) 來檢查DLL的依賴,並確保所有依賴都已經安裝並位於可搜索的路徑中。
3. 位數不匹配問題:如果Python解釋器的位數(32位或64位)與DLL的位數不匹配,也會導致載入失敗。確保Python解釋器和DLL的位數相同。如果你使用的是64位Python,也必須使用64位的DLL。
4. 檢查錯誤代碼:當ctypes無法載入DLL時,嘗試捕獲異常並列印出更多錯誤信息可能會有幫助。