Python的C/C++扩展
来源:互联网 发布:淘宝头条网页版 编辑:程序博客网 时间:2024/06/05 00:27
Python的C/C++扩展
By phidoit@gmail.com
可扩展性是Python的一大特色,一方面,由于Python是解释执行的,这导致运行速度会比编译型语言慢,因此可以通过使用C/C++重写核心部分代码以解决性能上的瓶颈(程序90%的时间再运行10%的代码);另一方面,可以通过扩展,达到添加整合一些额外的功能以及保持专有源代码的目的。在本文接下来的部分中我们将讨论如何编写C/C++扩展代码,并使用它们的功能。
我们要建立的是一个可以在Python内运行的C/C++模块,因此需要解决如何使C代码和Python代码能够进行交互以及数据共享。扩展是通过为C代码编写包装函数(类似适配器)实现双向交互和数据共享的。
一.一般的包装模式
每一个包装函数主要做三件事:
1.把输入的Python对象转换为C/C++对象;
2.调用C/C++函数;
3.转换C/C++函数处理的输出结果为Python对象,并返回;
先用一个简单样例描述模块大体的过程:
//wrap.cpp
//1.C代码
#include "Python.h"
int add(int arg1,int arg2)
{
return arg1 + arg2;
}
//2.add的包装函数:
static PyObject* wrap_add(PyObject*self, PyObject*args)
{
//把输入的Python对象转换为C/C++能识别的数据
int arg1, arg2;
if(!PyArg_ParseTuple(args,"ii", &arg1, &arg2))
return NULL;
//调用C/C++函数,得到结果
int result = add(arg1,arg2);
//把得到的结果包装成Python对象,并返回
return (PyObject*)Py_BuildValue("i", result);
}
//3.为模块添加PyMethodDef方法数组
static PyMethodDef wrap_methods[]={
{"add", wrap_add, METH_VARARGS},
{NULL,NULL}
};
//4.增加模块初始化函数InitModule
PyMODINIT_FUNC initwrap (void)
{
Py_InitModule("wrap ", wrap_methods);
}
把上面的代码编译,生成wrap.pyd。
Visual Studio 2005编译方法参考:
http://blog.csdn.net/solo_lxy/archive/2007/07/20/1700515.aspx
启动控制台切换到相应的工程目录,即可测试生成的模块:
(PS:似乎只有Release模式生成的模块才能正常运行)
相关说明
每个包装函数都有如下形式:
PyObject * wrap_function(PyObject *, PyObject * args)
函数第一个参数,有特殊用途,通常选择忽略。第二个参数是一个PyTuple(PyObject的子类型,和Python中的Tuple对应),是调用时Python传入的参数。
函数PyArg_ParseTuple把Python对象转换为C的数据类型,其声明如下:
int PyArg_ParseTuple(PyObject* args, char* format, ...);
参数args必须是一个tuple对象,包含传递过来的参数, format 参数必须是格式化字符串。剩余参数是各个变量的地址,类型要与格式化字符串对应。如:
int arg1, arg2;
PyArg_ParseTuple(args, "ii", &arg1, &arg2);
函数Py_BuildValue可以说是PyArg_ParseTuple的逆过程,它把C的数据类型包装为Python对象。
return (PyObject*)Py_BuildValue("i", result);
把调用C函数的结果result包装为Python的int对象,并返回。
static PyMethodDef wrap_methods[] ={
{"add", wrap_add, METH_VARARGS},
{NULL, NULL}
};
这个数组包含多个数组,其中的每个数组都包含了一个函数的信息,以便解释器能够导入并调用它们,最后一个NULL数组表示列表的结束。METH_VARARGS常量表示参数以元组形式传入。
PyMODINIT_FUNC initwrap (void)
{
Py_InitModule("wrap ", wrap_methods);
}
模块初始化函数void initModuleName(),这部分代码在模块被导入的时候被解释器调用。这样所有的包装就已经完成了。
二.C++类的包装
// Example.cpp
class Numbers
{
public:
Numbers(int first,double second)
: m_first( first), m_second(second){}
double NumMemberMult(void){return m_first*m_second;}
private:
int m_first;
double m_second;
};
static void PyDelNumbers(void*ptr)
{
Numbers * oldnum = static_cast<Numbers*>(ptr);
delete oldnum;
return;
}
PyObject *Example_new_Numbers(PyObject*, PyObject* args)
{
int arg1;
double arg2;
int ok = PyArg_ParseTuple(args,"id",&arg1,&arg2);
if(!ok)return NULL;
//动态创建一个新对象
Numbers *newnum = new Numbers(arg1, arg2);
//把指针newnum包装成PyCObject对象并返回给解释器
return PyCObject_FromVoidPtr( newnum, PyDelNumbers);
}
PyObject * Example_Numbers_MemberMult(PyObject*, PyObject* args)
{
PyObject *pynum = 0;
int ok = PyArg_ParseTuple( args,"O", &pynum);
if(!ok)return NULL;
//把PyCObject转换为void指针
void * temp= PyCObject_AsVoidPtr(pynum);
//把void指针转换为一个Numbers对象指针
Numbers * thisnum = static_cast<Numbers*>(temp);
//调用函数
double result = thisnum->NumMemberMult();
//返回结果
return Py_BuildValue("d",result);
}
static PyMethodDef Example_methods[]= {
{"Numbers", Example_new_Numbers, METH_VARARGS},
{"NumMemberMult", Example_Numbers_MemberMult, METH_VARARGS},
{NULL,NULL}
};
PyMODINIT_FUNC initExample (void)
{
Py_InitModule("Example", Example_methods);
}
C++类的包装和C函数的包装大同小异,因为对类的包装是对函数的包装,所以仍需要用Python代码对扩展模块进行包装,才可以像类一样的使用。
#example.py
from Example import*
class example(object):
def __init__(self,arg1,arg2):
self._base = Numbers(arg1,arg2)
def MemberMult(self):
return NumMemberMult(self._base)
这样C++类的包装也完成了。
三.C/C++中创建Python list
static PyObject* Windy_dict(PyObject*self, PyObject*args)
{
//创建列表
PyObject *newlist = PyList_New(0);
PyList_Append(newlist, PyString_FromString("first"));
PyList_Append(newlist, PyString_FromString("second"));
PyList_Append(newlist, PyString_FromString("third"));
//返回给解释器
return newlist;
}
创建其它Python对象也类似list的创建,返回给解释器的都是一个对象指针。C/C++对Python对象的解析差不多是创建时的逆过程。具体的对象模型及API可以查阅相关参考文档。
Python v2.6.2 documentation » Python/C API Reference Manual » Concrete Objects Layer
0 0
- Python的C扩展
- Python 的C语言扩展
- python的C、c++扩展
- Python的C/C++扩展
- python的C、c++扩展
- Python的C/C++扩展
- Python的C/C++扩展
- Python的C扩展问题
- 创建python的c扩展
- 用c扩展python
- C扩展python实例
- C语言扩展Python
- C语言扩展Python
- python c扩展
- Python:C语言扩展
- Python 扩展C
- python之C扩展
- python C/C++ 扩展
- java读取xml获得list并通过反射赋值给javabean
- Linux下串口通讯编程
- do your best Xuzho
- League Cup five giants third round appearance in F
- RTS/CTS的機制
- Python的C/C++扩展
- Android Chromium for WebView代码结构
- Mac电脑 重设开机密码
- github优秀开源项目大全-iOS
- ioremap mmap
- openwrt中添加自定义驱动模块 .
- KMP算法
- WPA/WPA2密钥派生与分发
- ServletContextListener 和HttpSessionListener 的自我理解