小结两种在Python中导入C语言扩展库的方法
2015-05-29 16:35
225 查看
一种是Python文档的推荐方案,采用C API扩展写法:
在D:建一个add.c文件,输入
[cpp] view
plaincopy
//add.c
//
#include <Python.h>;
static PyObject* add(PyObject *self, PyObject *args);
//一定声明为static,把他们限制在这个文件范围里。 几乎所有的参数都是PyObject类型。 在python,每个东西都是object。
static PyObject* add(PyObject* self, PyObject* args)
{
int x=0 ;
int y=0;
int z=0;
if (! PyArg_ParseTuple(args, "i|i", &x, &y))
return NULL;
/*第一个参数是self,这个是python用的, 每个函数都要有。我们暂时不管。args是一个参数列表。她把所有的参数都整合成一个string。所以
我们需要从这个string里来解析我们的参数。PyArg_ParseTuple来完成这个任务。第一个参数是args, 就是我们要转换的参数。第二个是格式符号。
“s”代表是个string。 从args里提取一个参数就写"s", 两个的话就写"s|s", 如果是一个string,一个int,就写"s|i", 和printf差不多。第三个
参数就是提取出来的参数放置的真正位置。必须传递这个参数的地址。对于add, 他将提取两个参数。分别是x和y。*/
z=x+y;
return Py_BuildValue("i", z);
/*调用完之后我们需要返回结果。这个结果是c的type或者是我们自己定义的类型。必须把他转换成PyObject, 让python认识。这个用Py_BuildValue
来完成。他是PyArg_ParseTuple的逆过程。他的第一个参数和PyArg_ParseTuple的第二个参数一样, 是个格式化符号。第三个参数
是我们需要转换的参数。Py_BuildValue会把所有的返回只组装成一个tutple给python。*/
}
static PyMethodDef addMethods[] =
{
{"add", add, METH_VARARGS, "Execute a shell command."},
{NULL, NULL, 0, NULL}
};
/*这个是一个c的结构。他来完成一个映射。 我们需要把我们扩展的函数都映射到这个表里。表的第一个字段是python真正认识的。是python
里的方法名字。 第二个字段是python里的这个方法名字的具体实现的函数名。 在python里调用add, 真正执行的是用c写的add函数。
第三个字段是METH_VARARGS, 他告诉python,add是调用c函数来实现的。第四个字段是这个函数的说明。如果你在python里来help这个函数,
将显示这个说明。相当于在python里的函数的文档说明。*/
PyMODINIT_FUNC initadd()
{
Py_InitModule("add", addMethods);
}
/*注意,这个函数的名字不能改动。 必须是init+模块名字。 我们的模块名字是add。所以这个函数是initadd()。
这样python在导入add 的模块时候,才会找到这个函数,并调用。这个函数调用Py_InitModule来将模块名字和映射表结合在一起。
他表示,add这个模块使用addMethods这个映射表。python应该这样导入我们的module的.*/
然后在D:盘建立setup.py
[python] view
plaincopy
from distutils.core import setup, Extension
module1 = Extension('add', sources = ['add.c'])
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
plaincopy
//spam.c
//
#include <windows.h>
BOOL APIENTRY
DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
return TRUE;
}
__declspec(dllexport) int
multiply(int num1, int num2)
{
return num1 * num2;
}
//这是一个标准的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
plaincopy
char *foo(){
char *p = "hello world";
return p;
}
void foo1(char *p){
strcpy(p, "hello world");
}
编译:$ gcc -o libspam.so -fpic -shared spam.c
进入Python:
[python] view
plaincopy
#返回指针:
>>> import ctypes
>>> hello = ctypes.cdll.LoadLibrary("/home/Henry/libspam.so")
>>> p = hello.foo()
>>> ctypes.c_char_p(p).value
>>> 'hello world'
#传入buffer:
>>> b = ctypes.create_string_buffer(12)
>>> hello.foo1(b)
>>> b.value
>>> 'hello world'
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
但是ctypes对C++的DLL导入不行。对于C++库的导入还是要借助于Boost.python。
我一定会回来的!
在D:建一个add.c文件,输入
[cpp] view
plaincopy
//add.c
//
#include <Python.h>;
static PyObject* add(PyObject *self, PyObject *args);
//一定声明为static,把他们限制在这个文件范围里。 几乎所有的参数都是PyObject类型。 在python,每个东西都是object。
static PyObject* add(PyObject* self, PyObject* args)
{
int x=0 ;
int y=0;
int z=0;
if (! PyArg_ParseTuple(args, "i|i", &x, &y))
return NULL;
/*第一个参数是self,这个是python用的, 每个函数都要有。我们暂时不管。args是一个参数列表。她把所有的参数都整合成一个string。所以
我们需要从这个string里来解析我们的参数。PyArg_ParseTuple来完成这个任务。第一个参数是args, 就是我们要转换的参数。第二个是格式符号。
“s”代表是个string。 从args里提取一个参数就写"s", 两个的话就写"s|s", 如果是一个string,一个int,就写"s|i", 和printf差不多。第三个
参数就是提取出来的参数放置的真正位置。必须传递这个参数的地址。对于add, 他将提取两个参数。分别是x和y。*/
z=x+y;
return Py_BuildValue("i", z);
/*调用完之后我们需要返回结果。这个结果是c的type或者是我们自己定义的类型。必须把他转换成PyObject, 让python认识。这个用Py_BuildValue
来完成。他是PyArg_ParseTuple的逆过程。他的第一个参数和PyArg_ParseTuple的第二个参数一样, 是个格式化符号。第三个参数
是我们需要转换的参数。Py_BuildValue会把所有的返回只组装成一个tutple给python。*/
}
static PyMethodDef addMethods[] =
{
{"add", add, METH_VARARGS, "Execute a shell command."},
{NULL, NULL, 0, NULL}
};
/*这个是一个c的结构。他来完成一个映射。 我们需要把我们扩展的函数都映射到这个表里。表的第一个字段是python真正认识的。是python
里的方法名字。 第二个字段是python里的这个方法名字的具体实现的函数名。 在python里调用add, 真正执行的是用c写的add函数。
第三个字段是METH_VARARGS, 他告诉python,add是调用c函数来实现的。第四个字段是这个函数的说明。如果你在python里来help这个函数,
将显示这个说明。相当于在python里的函数的文档说明。*/
PyMODINIT_FUNC initadd()
{
Py_InitModule("add", addMethods);
}
/*注意,这个函数的名字不能改动。 必须是init+模块名字。 我们的模块名字是add。所以这个函数是initadd()。
这样python在导入add 的模块时候,才会找到这个函数,并调用。这个函数调用Py_InitModule来将模块名字和映射表结合在一起。
他表示,add这个模块使用addMethods这个映射表。python应该这样导入我们的module的.*/
然后在D:盘建立setup.py
[python] view
plaincopy
from distutils.core import setup, Extension
module1 = Extension('add', sources = ['add.c'])
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
plaincopy
//spam.c
//
#include <windows.h>
BOOL APIENTRY
DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
return TRUE;
}
__declspec(dllexport) int
multiply(int num1, int num2)
{
return num1 * num2;
}
//这是一个标准的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
plaincopy
char *foo(){
char *p = "hello world";
return p;
}
void foo1(char *p){
strcpy(p, "hello world");
}
编译:$ gcc -o libspam.so -fpic -shared spam.c
进入Python:
[python] view
plaincopy
#返回指针:
>>> import ctypes
>>> hello = ctypes.cdll.LoadLibrary("/home/Henry/libspam.so")
>>> p = hello.foo()
>>> ctypes.c_char_p(p).value
>>> 'hello world'
#传入buffer:
>>> b = ctypes.create_string_buffer(12)
>>> hello.foo1(b)
>>> b.value
>>> 'hello world'
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
但是ctypes对C++的DLL导入不行。对于C++库的导入还是要借助于Boost.python。
我一定会回来的!
相关文章推荐
- C++中 explicit的用法
- HDU-1034-Candy Sharing Game(C++ && 简单模拟)
- C/C++如何使用密码输入而不回显--getch()函数
- C++作业4.18
- 【干货】国外程序员整理的 C++ 资源大全–日常工作,我觉得用处确实很大,所以分享
- 【干货】国外程序员整理的 C++ 资源大全–日常工作,我觉得用处确实很大,所以分享
- C++ 写leetcode遇到的一些问题总结Implement strStr()
- C++读取并逐行显示txt内容
- C语言特性
- C/C++计时方法及精度
- C++中placement new
- VC++6.0 IDE的工程用Code::Blocks来打开、编译、调试终极配置方案
- c++原生的unicode支持
- 【 Sqrt(x) 】cpp
- C++转Java自学之路(四)文档注释、静态代码块与对象初始化过程
- C++智能指针分类及使用
- 小心C语言localtime和asctime时间函数陷阱
- C语言结构体中冒号的用法--C 位域
- C++知识点总结(四)——面向对象的编程细节总结
- C++知识点总结(四)——面向对象的编程细节总结