Python的C/C++扩展
生活随笔
收集整理的這篇文章主要介紹了
Python的C/C++扩展
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
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
總結
以上是生活随笔為你收集整理的Python的C/C++扩展的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用C语言扩展Python的功能的实例
- 下一篇: s3c2440移植MQTT