1. 程式人生 > >10 python 擴展

10 python 擴展

ets 例子 tin 出錯 lib 語言 是我 pst for

說起來擴展,基本就是在其他語言裏調用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_DLL
3 #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 擴展