10 python 擴展
說起來擴展,基本就是在其他語言裏調用C或者C++,因為這兩個是效率最高的代碼,而其他大多都是另外又封裝的,所以效率較低。
當出現語言本身無法解決的效率問題時,就需要擴展調用其他代碼。
因為我自己會C++,所以我就只記錄調用C++。
其中調用DLL最為簡單,所以在此自己mark一下。
正文開始:
C++中生成DLL就不廢話了。需要特別註意的是據我所知VS2010之前的版本貌似只能編譯成32位的DLL,但是我的電腦安裝的是64位的python,調用32位的就會出錯。
解決辦法就是用VS2010,在2010中可以編譯成64位的DLL。具體方法是在上邊的win32中選擇編輯新的方式,裏邊可以選。
接下來舉個簡單例子
1 //hello.h 2 #ifdef EXPORT_HELLO_DLL 3 #define HELLO_API __declspec(dllexport) 4 #else 5 #define HELLO_API __declspec(dllimport) 6 #endif 7 extern "C" 8 { 9 HELLO_API int IntAdd(int , int); 10 } 11 12 //hello.cpp 13 #define EXPORT_HELLO_DLL 14 #include "hello.h" 15 HELLO_API int IntAdd(int a, int b)16 { 17 return a + b; 18 }
上述是兩個文件,也就是C++中需要編譯DLL的文件。
1 from ctypes import * 2 dll = cdll.LoadLibrary(‘hello.dll‘) 3 ret = dll.IntAdd(2, 4) 4 print(ret)
上述是調用DLL文件的代碼,其實就是用到了ctypes庫。
以上是一個"hello world"級別的程序,實際運用中更多的需要傳遞數據結構、字符串等,才能滿足我們的需求。那麽本示例將展示,如何傳遞數據結構參數,以及如何通過數據結構獲取返回值。
1 //hello.h 2 #ifdef EXPORT_HELLO_DLL3 #define HELLO_API __declspec(dllexport) 4 #else 5 #define HELLO_API __declspec(dllimport) 6 #endif 7 8 #define ARRAY_NUMBER 20 9 #define STR_LEN 20 10 11 struct StructTest 12 { 13 int number; 14 char* pChar; 15 char str[STR_LEN]; 16 int iArray[ARRAY_NUMBER]; 17 }; 18 19 extern "C" 20 { 21 //HELLO_API int IntAdd(int , int); 22 HELLO_API char* GetStructInfo(struct StructTest* pStruct); 23 } 24 25 //hello.cpp 26 #include <string.h> 27 #define EXPORT_HELLO_DLL 28 #include "hello.h" 29 30 HELLO_API char* GetStructInfo(struct StructTest* pStruct) 31 { 32 for (int i = 0; i < ARRAY_NUMBER; i++) 33 pStruct->iArray[i] = i; 34 pStruct->pChar = "hello python!"; 35 strcpy (pStruct->str, "hello world!"); 36 pStruct->number = 100; 37 return "just OK"; 38 }
GetStructInfo這個函數通過傳遞一個StructTest類型的指針,然後對對象中的屬性進行賦值,最後返回"just OK".
編寫Python調用代碼如下,首先在Python中繼承Structure構造一個和C DLL中一致的數據結構StructTest,然後設置函數GetStructInfo的參數類型和返回值類型,最後創建一個StructTest對象,並將其轉化為指針作為參數,調用函數GetStrcutInfo,最後通過輸出數據結構的值來檢查是否調用成功:
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;
最後要說一點,這些內容不是原創,只是我用別人的方法,自己驗證時候遇到的問題,比如64位DLL的問題。
http://blog.csdn.net/bluehawksky/article/details/39082125 更詳細的各種數據結構的傳遞可以看這個。
10 python 擴展