用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对象进行管理:

[python]
  1. 1:refcount.py  
  2. class refcount:  
  3.     # etc.   
  4. r1 = refcount() # 引用计数为1   
  5. r2 = r1         # 引用计数为2   
  6. del(r1)         # 引用计数为1   
  7. del(r2)         # 引用计数为0,删除对象   
  8.   
  9.    

在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的这三种数据类型:

[cpp]
  1. 例2:typeifs.c  
  2. // build an integer   
  3. PyObject* pInt = Py_BuildValue("i", 2003);  
  4. assert(PyInt_Check(pInt));  
  5. int i = PyInt_AsLong(pInt);  
  6. Py_DECREF(pInt);  
  7. // build a float   
  8. PyObject* pFloat = Py_BuildValue("f", 3.14f);  
  9. assert(PyFloat_Check(pFloat));  
  10. float f = PyFloat_AsDouble(pFloat);  
  11. Py_DECREF(pFloat);  
  12. // build a string   
  13. PyObject* pString = Py_BuildValue("s""Python");  
  14. assert(PyString_Check(pString);  
  15. int nLen = PyString_Size(pString);  
  16. char* s = PyString_AsString(pString);  
  17. Py_DECREF(pString);  
  18.   
  19.    

2.3.2 元组

Python语言中的元组是一个长度固定的数组,当Python解释器调用C语言扩展中的方法时,所有非关键字(non-keyword)参数都以元组方式进行传递。下面的例子示范了如何在C语言中使用Python的元组类型:

[cpp]
  1. 例3:typetuple.c  
  2. // create the tuple   
  3. PyObject* pTuple = PyTuple_New(3);  
  4. assert(PyTuple_Check(pTuple));  
  5. assert(PyTuple_Size(pTuple) == 3);  
  6. // set the item   
  7. PyTuple_SetItem(pTuple, 0, Py_BuildValue("i", 2003));  
  8. PyTuple_SetItem(pTuple, 1, Py_BuildValue("f", 3.14f));  
  9. PyTuple_SetItem(pTuple, 2, Py_BuildValue("s""Python"));  
  10. // parse tuple items   
  11. int i;  
  12. float f;  
  13. char *s;  
  14. if (!PyArg_ParseTuple(pTuple, "ifs", &i, &f, &s))  
  15.     PyErr_SetString(PyExc_TypeError, "invalid parameter");  
  16. // cleanup   
  17. Py_DECREF(pTuple);  
  18.   
  19.    

2.3.3 列表

Python语言中的列表是一个长度可变的数组,列表比元组更为灵活,使用列表可以对其存储的Python对象进行随机访问。下面的例子示范了如何在C语言中使用Python的列表类��:

[cpp]
  1. 例4:typelist.c  
  2. // create the list   
  3. PyObject* pList = PyList_New(3); // new reference   
  4. assert(PyList_Check(pList));  
  5. // set some initial values   
  6. for(int i = 0; i < 3; ++i)  
  7.     PyList_SetItem(pList, i, Py_BuildValue("i", i));  
  8. // insert an item   
  9. PyList_Insert(pList, 2, Py_BuildValue("s""inserted"));  
  10. // append an item   
  11. PyList_Append(pList, Py_BuildValue("s""appended"));  
  12. // sort the list   
  13. PyList_Sort(pList);  
  14. // reverse the list   
  15. PyList_Reverse(pList);  
  16. // fetch and manipulate a list slice   
  17. PyObject* pSlice = PyList_GetSlice(pList, 2, 4); // new reference   
  18. for(int j = 0; j < PyList_Size(pSlice); ++j) {  
  19.   PyObject *pValue = PyList_GetItem(pList, j);  
  20.   assert(pValue);  
  21. }  
  22. Py_DECREF(pSlice);  
  23. // cleanup   
  24. Py_DECREF(pList);  
  25.   
  26.    

2.3.4 字典

Python语言中的字典是一个根据关键字进行访问的数据类型。下面的例子示范了如何在C语言中使用Python的字典类型:

[cpp]
  1. 例5:typedic.c  
  2. // create the dictionary   
  3. PyObject* pDict = PyDict_New(); // new reference   
  4. assert(PyDict_Check(pDict));  
  5. // add a few named values   
  6. PyDict_SetItemString(pDict, "first",   
  7.                      Py_BuildValue("i", 2003));  
  8. PyDict_SetItemString(pDict, "second",   
  9.                      Py_BuildValue("f", 3.14f));  
  10. // enumerate all named values   
  11. PyObject* pKeys = PyDict_Keys(); // new reference   
  12. for(int i = 0; i < PyList_Size(pKeys); ++i) {  
  13.   PyObject *pKey = PyList_GetItem(pKeys, i);  
  14.   PyObject *pValue = PyDict_GetItem(pDict, pKey);  
  15.   assert(pValue);  
  16. }  
  17. Py_DECREF(pKeys);  
  18. // remove a named value   
  19. PyDict_DelItemString(pDict, "second");  
  20. // cleanup   
  21. Py_DECREF(pDict);  
  22.   
  23.     

相关推荐