说起来扩展,基本就是在其他语言里调用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 更详细的各种数据结构的传递可以看这个。