小结两种在Python中导入C语言扩展库的方法

小结两种在Python中导入C语言扩展库的方法

分类: Pythoner   2563人阅读  评论(1)  收藏  举报

一种是Python文档的推荐方案,采用C API扩展写法:

在D:建一个add.c文件,输入

[cpp]  view plain copy
  1. //add.c  
  2.   
  3. //  
  4.   
  5. #include <Python.h>;  
  6.   
  7. static PyObject* add(PyObject *self, PyObject *args);   
  8. //一定声明为static,把他们限制在这个文件范围里。 几乎所有的参数都是PyObject类型。 在python,每个东西都是object。   
  9.   
  10. static PyObject* add(PyObject* self, PyObject* args)   
  11. {   
  12.    int x=0 ;   
  13.    int y=0;  
  14.    int z=0;  
  15.  if (! PyArg_ParseTuple(args, "i|i", &x, &y))  
  16.   return NULL;  
  17.  /*第一个参数是self,这个是python用的, 每个函数都要有。我们暂时不管。args是一个参数列表。她把所有的参数都整合成一个string。所以  
  18.  我们需要从这个string里来解析我们的参数。PyArg_ParseTuple来完成这个任务。第一个参数是args, 就是我们要转换的参数。第二个是格式符号。 
  19.  “s”代表是个string。 从args里提取一个参数就写"s", 两个的话就写"s|s", 如果是一个string,一个int,就写"s|i", 和printf差不多。第三个 
  20.  参数就是提取出来的参数放置的真正位置。必须传递这个参数的地址。对于add, 他将提取两个参数。分别是x和y。*/  
  21. z=x+y;  
  22. return Py_BuildValue("i", z);  
  23.     /*调用完之后我们需要返回结果。这个结果是c的type或者是我们自己定义的类型。必须把他转换成PyObject, 让python认识。这个用Py_BuildValue  
  24.  来完成。他是PyArg_ParseTuple的逆过程。他的第一个参数和PyArg_ParseTuple的第二个参数一样, 是个格式化符号。第三个参数  
  25.  是我们需要转换的参数。Py_BuildValue会把所有的返回只组装成一个tutple给python。*/  
  26. }   
  27.   
  28. static PyMethodDef addMethods[] =  
  29. {   
  30.    {"add",  add, METH_VARARGS, "Execute a shell command."},   
  31.    {NULL, NULL, 0, NULL}  
  32. };   
  33. /*这个是一个c的结构。他来完成一个映射。 我们需要把我们扩展的函数都映射到这个表里。表的第一个字段是python真正认识的。是python  
  34. 里的方法名字。 第二个字段是python里的这个方法名字的具体实现的函数名。 在python里调用add, 真正执行的是用c写的add函数。 
  35. 第三个字段是METH_VARARGS, 他告诉python,add是调用c函数来实现的。第四个字段是这个函数的说明。如果你在python里来help这个函数, 
  36. 将显示这个说明。相当于在python里的函数的文档说明。*/  
  37.   
  38. PyMODINIT_FUNC initadd()   
  39. {   
  40.        Py_InitModule("add", addMethods);   
  41. }   
  42. /*注意,这个函数的名字不能改动。 必须是init+模块名字。 我们的模块名字是add。所以这个函数是initadd()。 
  43. 这样python在导入add 的模块时候,才会找到这个函数,并调用。这个函数调用Py_InitModule来将模块名字和映射表结合在一起。  
  44. 他表示,add这个模块使用addMethods这个映射表。python应该这样导入我们的module的.*/  

 

然后在D:盘建立setup.py

[python]  view plain copy
  1. from distutils.core import setup, Extension  
  2.   
  3. module1 = Extension('add', sources = ['add.c'])  
  4.   
  5. setup (name = 'PackageName', version = '1.0', description = 'This is a ADD package', ext_modules = [module1])  

 

将cmd切换到D:

输入setup.py build --compiler=mingw32 -verbose

这里我选择了mingw32,否则在我的机器上它会用msvc,而这会有一些小错误

运行成功后会在(当前目录的)D:/build/lib.win32-2.6下生成add.pyd

 

下面就在Python中导入

>>> import sys
>>> sys.path.append("D:/build/lib.win32-2.6")

>>> import add
>>> add.add(3,2)
5

 

Bingo!

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

 

以上是用C API的扩展方式,它的写法比较麻烦。以下用ctypes直接导入dll模块。

 

如果是在Windows下面:

首先在D:建立文件spam.c

[cpp]  view plain copy
  1. //spam.c  
  2.   
  3. //  
  4.   
  5. #include <windows.h>  
  6.   
  7. BOOL APIENTRY  
  8. DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)  
  9. {  
  10.  return TRUE;  
  11. }  
  12.   
  13. __declspec(dllexportint  
  14. multiply(int num1, int num2)  
  15. {  
  16.  return num1 * num2;  
  17. }  
  18.   
  19. //这是一个标准的Windows DLL的写法。  

 

我用cl来编译它,现在我渐渐喜欢上了用cl来编译,省得建一个好几兆的项目,而且参数可以灵活选择。后面我会继续学习如何写make file。

在cmd输入cl -I"d:/programs/python26/include" spam.cpp,会生成spam.obj

再输入link spam.obj /DLL /libpath:"d:/programs/python26/libs",生成spam.dll

 

下面到python中导入:

>>> import ctypes
>>> cdll=ctypes.cdll.LoadLibrary('d:/spam.dll')

>>> cdll.multiply(2,3)
6

 

如果是在Linux下面:

在/home/Henry下建立spam.c

[cpp]  view plain copy
  1. char *foo(){     
  2.     char *p = "hello world";     
  3.     return p;     
  4. }     
  5.     
  6. void foo1(char *p){     
  7.     strcpy(p, "hello world");     
  8. }    

编译:$ gcc -o libspam.so -fpic -shared spam.c

进入Python:

[python]  view plain copy
  1. #返回指针:   
  2. >>> import ctypes   
  3. >>> hello = ctypes.cdll.LoadLibrary("/home/Henry/libspam.so")   
  4. >>> p = hello.foo()  
  5. >>> ctypes.c_char_p(p).value   
  6. >>> 'hello world'   
  7.   
  8. #传入buffer:   
  9. >>> b = ctypes.create_string_buffer(12)   
  10. >>> hello.foo1(b)   
  11. >>> b.value   
  12. >>> 'hello world'   

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

 

但是ctypes对C++的DLL导入不行。对于C++库的导入还是要借助于Boost.python。

我一定会回来的!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值