如何将c语⾔程序封装供python调⽤_转:⽤C语⾔扩展Python
的功能
⼀、简介
Python是⼀门功能强⼤的⾼级脚本语⾔,它的强⼤不仅表现在其⾃⾝的功能上,⽽且还表现在其良好的可扩展性上,正因如此,Python已经开始受到越来越多⼈的青睐,并且被屡屡成功地应⽤于各类⼤型软件系统的开发过程中。
与其它普通脚本语⾔有所不同,Python程序员可以借助Python语⾔提供的API,使⽤C或者C++来对Python进⾏功能性扩展,从⽽即可以利⽤Python⽅便灵活的语法和功能,⼜可以获得与C或者C++⼏乎相同的执⾏性能。执⾏速度慢是⼏乎所有脚本语⾔都具有的共性,也是倍受⼈们指责的⼀个重要因素,Python则通过与C语⾔的有机结合巧妙地解决了这⼀问题,从⽽使脚本语⾔的应⽤范围得到了很⼤扩展。
在⽤Python开发实际软件系统时,很多时候都需要使⽤C/C++来对Python进⾏扩展。最常见的情况是⽬前已经存在⼀个⽤C编写的库,需要在Python语⾔中使⽤该库的某些功能,此时就可以借助Python提供的扩展功能来实现。此外,由于Python从本质上讲还是⼀种脚本语⾔,某些功能⽤Python实现可能很难
满⾜实际软件系统对执⾏效率的要求,此时也可以借助Python提供的扩展功能,将这些关键代码段⽤C或者C++实现,从⽽提供程序的执⾏性能。
本⽂主要介绍Python提供的C语⾔扩展接⼝,以及如何使⽤这些接⼝和C/C++语⾔来对Python进⾏功能性扩展,并辅以具体的实例讲述如何实现Python的功能扩展。
⼆、Python的C语⾔接⼝
Python是⽤C语⾔实现的⼀种脚本语⾔,本⾝具有优良的开放性和可扩展性,并提供了⽅便灵活的应⽤程序接⼝(API),从⽽使得C/C++程序员能够在各个级别上对Python解释器的功能进⾏扩展。在使⽤C/C++对Python进⾏功能扩展之前,必须⾸先掌握Python解释所提供的C语⾔接⼝。
2.1 Python对象(PyObject)
Python是⼀门⾯向对象的脚本语⾔,所有的对象在Python解释器中都被表⽰成PyObject,PyObject结构包含Python对象的所有成员指针,并且对Python对象的类型信息和引⽤计数进⾏维护。在进⾏Python的扩展编程时,⼀旦要在C或者C++中对Python对象进⾏处理,就意味着要维护⼀个PyObject结构。
在Python的C语⾔扩展接⼝中,⼤部分函数都有⼀个或者多个参数为PyObject指针类型,并且返回值
也⼤都为PyObject指针。
2.2 引⽤计数
为了简化内存管理,Python通过引⽤计数机制实现了⾃动的垃圾回收功能,Python中的每个对象都有⼀个引⽤计数,⽤来计数该对象在不同场所分别被引⽤了多少次。每当引⽤⼀次Python对象,相应的引⽤计数就增1,每当消毁⼀次Python对象,则相应的引⽤就减1,只有当引⽤计数为零时,才真正从内存中删除Python对象。
下⾯的例⼦说明了Python解释器如何利⽤引⽤计数来对Pyhon对象进⾏管理:
例1:refcount.py
class refcount:
# etc.
r1 = refcount() # 引⽤计数为1
r2 = r1 # 引⽤计数为2
del(r1) # 引⽤计数为1
del(r2) # 引⽤计数为0,删除对象
在C/C++中处理Python对象时,对引⽤计数进⾏正确的维护是⼀个关键问题,处理不好将很容易产⽣内存泄漏。Python的C语⾔接⼝提供了⼀些宏来对引⽤计数进⾏维护,最常见的是⽤Py_INCREF()来增加使Python对象的引⽤计数增1,⽤Py_DECREF()来使Python对象的引⽤计数减1。
2.3 数据类型
Python定义了六种数据类型:整型、浮点型、字符串、元组、列表和字典,在使⽤C语⾔对Python进⾏功能扩展时,⾸先要了解如何在C 和Python的数据类型间进⾏转化。
2.3.1 整型、浮点型和字符串
在Python的C语⾔扩展中要⽤到整型、浮点型和字符串这三种数据类型时相对⽐较简单,只需要知道如何⽣成和维护它们就可以了。下⾯的例⼦给出了如何在C语⾔中使⽤Python的这三种数据类型:
例2:typeifs.c
// build an integer
PyObject* pInt = Py_BuildValue("i", 2003);
assert(PyInt_Check(pInt));
int i = PyInt_AsLong(pInt);
Py_DECREF(pInt);
// build a float
PyObject* pFloat = Py_BuildValue("f", 3.14f);
assert(PyFloat_Check(pFloat));
float f = PyFloat_AsDouble(pFloat);
Py_DECREF(pFloat);
// build a string
PyObject* pString = Py_BuildValue("s", "Python");
assert(PyString_Check(pString);
int nLen = PyString_Size(pString);
char* s = PyString_AsString(pString);
Py_DECREF(pString);
2.3.2 元组
Python语⾔中的元组是⼀个长度固定的数组,当Python解释器调⽤C语⾔扩展中的⽅法时,所有⾮关键字(non-keyword)参数都以元组⽅式进⾏传递。下⾯的例⼦⽰范了如何在C语⾔中使⽤Python的元组类型:
例3:typetuple.c
// create the tuple
PyObject* pTuple = PyTuple_New(3);
assert(PyTuple_Check(pTuple));
assert(PyTuple_Size(pTuple) == 3);
// set the item
PyTuple_SetItem(pTuple, 0, Py_BuildValue("i", 2003));
PyTuple_SetItem(pTuple, 1, Py_BuildValue("f", 3.14f));
PyTuple_SetItem(pTuple, 2, Py_BuildValue("s", "Python"));
// parse tuple items
int i;
float f;
char *s;
if (!PyArg_ParseTuple(pTuple, "ifs", &i, &f, &s))
PyErr_SetString(PyExc_TypeError, "invalid parameter");
/
/ cleanup
Py_DECREF(pTuple);
2.3.3 列表
Python语⾔中的列表是⼀个长度可变的数组,列表⽐元组更为灵活,使⽤列表可以对其存储的Python对象进⾏随机访问。下⾯的例⼦⽰范了如何在C语⾔中使⽤Python的列表类型:
例4:typelist.c
// create the list
PyObject* pList = PyList_New(3); // new reference
assert(PyList_Check(pList));
// set some initial values
for(int i = 0; i < 3; ++i)
PyList_SetItem(pList, i, Py_BuildValue("i", i));
// insert an item
PyList_Insert(pList, 2, Py_BuildValue("s", "inserted"));
// append an item
PyList_Append(pList, Py_BuildValue("s", "appended"));
// sort the list
PyList_Sort(pList);
// reverse the list
PyList_Reverse(pList);
// fetch and manipulate a list slice
PyObject* pSlice = PyList_GetSlice(pList, 2, 4); // new reference
for(int j = 0; j < PyList_Size(pSlice); ++j) {
PyObject *pValue = PyList_GetItem(pList, j);
assert(pValue);
}
Py_DECREF(pSlice);
// cleanup
Py_DECREF(pList);
2.3.4 字典
Python语⾔中的字典是⼀个根据关键字进⾏访问的数据类型。下⾯的例⼦⽰范了如何在C语⾔中使⽤Python的字典类型:
例5:typedic.c
// create the dictionary
PyObject* pDict = PyDict_New(); // new reference
assert(PyDict_Check(pDict));
// add a few named values
PyDict_SetItemString(pDict, "first",
Py_BuildValue("i", 2003));
PyDict_SetItemString(pDict, "second",
Py_BuildValue("f", 3.14f));
// enumerate all named values
PyObject* pKeys = PyDict_Keys(); // new reference
for(int i = 0; i < PyList_Size(pKeys); ++i) {
PyObject *pKey = PyList_GetItem(pKeys, i);
PyObject *pValue = PyDict_GetItem(pDict, pKey);
assert(pValue);
}
Py_DECREF(pKeys);
// remove a named value
PyDict_DelItemString(pDict, "second");
// cleanup
Py_DECREF(pDict);
三、Python的C语⾔扩展
3.1 模块封装
在了解了Python的C语⾔接⼝后,就可以利⽤Python解释器提供的这些接⼝来编写Python的C语⾔扩展,假设有如下⼀个C语⾔函数:例6:example.c
int fact(int n)
{
if (n <= 1)
return 1;
else
return n * fact(n - 1);
}
该函数的功能是计算某个给定⾃然数的阶乘,如果想在Python解释器中调⽤该函数,则应该⾸先将其实现为Python中的⼀个模块,这需要编写相应的封装接⼝,如下所⽰:
例7: wrap.c
#include
PyObject* wrap_fact(PyObject* self, PyObject* args)
{
int n, result;
if (! PyArg_ParseTuple(args, "i:fact", &n))
return NULL;
result = fact(n);
return Py_BuildValue("i", result);
}
static PyMethodDef exampleMethods[] =
{编程先学c语言还是python
{"fact", wrap_fact, METH_VARARGS, "Caculate N!"},
{NULL, NULL}
};
void initexample()
{
PyObject* m;
m = Py_InitModule("example", exampleMethods);
}
⼀个典型的Python扩展模块⾄少应该包含三个部分:导出函数、⽅法列表和初始化函数。
3.2 导出函数
要在Python解释器中使⽤C语⾔中的某个函数,⾸先要为其编写相应的导出函数,上述例⼦中的导出函数为wrap_fact。在Python的C语⾔扩展中,所有的导出函数都具有相同的函数原型:
PyObject* method(PyObject* self, PyObject* args);
该函数是Python解释器和C函数进⾏交互的接⼝,带有两个参数:self和args。参数self只在C函数被实现为内联⽅法(built-in method)时才被⽤到,通常该参数的值为空(NULL)。参数args中包含了Python解
释器要传递给C函数的所有参数,通常使⽤Python的C语⾔扩展接⼝提供的函数PyArg_ParseTuple()来获得这些参数值。
所有的导出函数都返回⼀个PyObject指针,如果对应的C函数没有真正的返回值(即返回值类型为void),则应返回⼀个全局的None对象(Py_None),并将其引⽤计数增1,如下所⽰:
PyObject* method(PyObject *self, PyObject *args)
{
Py_INCREF(Py_None);
return Py_None;

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。