使用C++編寫python擴展模塊

 簡介php

長話短說,這裏說的擴展Python功能與直接用其它語言寫一個動態連接庫,而後讓Python來調用有點不同(雖然本質是同樣的)。而是指使用Python自己提供的API,使用C++來對Python進行功能性擴展,能夠這樣理解,使用更高效的語言實現一些算法計算等等須要更高執行效率的核心(或者須要與系統進行密切交互的)模塊,而後讓Python像調用內建標準庫的方式來調用這些模塊,聽起來是否是很誘人?!在軟件技術高速發展的今天,藉助幾種計算機語言來實現一個系統的例子數不勝數,目的不外乎就是性能和便利的平衡。譬如本文要討論的使用C++來擴展Python就是PythonC++的一種巧妙的有機結合,好處不言而喻,既能夠得到和C++類似的執行性能,又能夠利用Python的開發靈活性。因爲Python自己是使用C實現的,兩者結合起來仍是比較容易的。python

 

基本流程linux

本文不適合這樣的讀者——對Python徹底不瞭解或者對C\C++徹底不瞭解,道理大家懂的。另外就是Python裏面有6種基本數據類型。你須要瞭解如何在CPython之間對這些類型進行轉化(這不在本文討論範圍,能夠參考[1])。算法

 

言歸正傳,感受前面說得太多了,實際上很簡單,所以我決定少說多作。一個C++Python擴展模塊至少應該有導出函數方法列表初始化函數三個部分。咱們用VS2005這個強大的工具開工!通常來講,你應該建一個Dll工程(至於使用exe來擴展Python能夠不能夠,暫時還沒研究過)。下面循序漸進的說明(關鍵說明在註釋部分)。shell

1、初始化函數數組

//-------------------------------------------------------------------------函數

// 函數        : initPyExt工具

// 功能        : 初始化函數性能

// 返回值     :PyMODINIT_FUNCui

// 附註        : 注意,這個函數的名字不能改動。必須是init+模塊名字,

// 咱們的模塊名字是PyExt,因此函數名是initPyExtPython在導入

// 咱們的PyExt模塊時,會找到這個函數,並調用。這個函數實現的

// 功能很簡單,經過調用Py_InitModule將模塊名字和映射表結合起

// 來,它的意思是說PyExt這個模塊使用PyExtMethods這個映射表。

//-------------------------------------------------------------------------

PyMODINIT_FUNCinitPyExt()

{

       Py_InitModule("PyExt",PyExtMethods);

}

 

2、方法列表

/*

      方法列表,這個是一個C結構數組。把須要擴展的函數都映射到這個表裏。

      那麼Python就知道你的這個擴展模塊支持一些什麼方法了。表的第一個字

      段是方法名字,也是經過Python來調用時的名字。第二個字段是導出函數,

      是真正調用的函數,也是C\C++實現的函數。第三個參數是指明Python

      C\C++函數傳遞參數的形式。可選的兩種方式是METH_VARARGS

      METH_KEYWORDS,其中METH_VARARGS是參數傳遞的標準形式,它通

      Python的元組在Python解釋器和C函數之間傳遞參數,若採用

      METH_KEYWORD方式,則Python解釋器和C函數之間將經過Python的字典

      類型在二者之間進行參數傳遞。第四個字段是這個函數的說明。若是你在

      python裏來help這個函數,將顯示這個說明。至關於在python裏的函數的文檔說明。

*/

staticPyMethodDefPyExtMethods[]=

{

       {"Add"Add,METH_VARARGS,"Addtwo  number - edit by magictong."},

       {"ExecSystem",ExecSystem,METH_VARARGS,"Execute  a shell command - edit bymagictong." },

       {NULL,NULL, 0,NULL}

};

 

3、導出函數

//-------------------------------------------------------------------------

// 函數        : Add

// 功能        : 這是一個加法函數

// 返回值     :PyObject*

// 參數        : PyObject*self 這個參數咱們暫時不用理會

// 參數        : PyObject*args 是一個參數列表,咱們須要從它解析出參數

// 附註        :

// 全部的導出函數都具備相同的原型:

// PyObject*method(PyObject* self, PyObject* args);

//PyArg_ParseTuple來完成解析參數任務。它的第一個參數是args

// 就是咱們要轉換的參數。第二個是格式符號。"s"表明是個string

// args裏提取一個參數就寫"s",兩個的話就寫"s|s",若是是一個

// string,一個int,就寫"s|i",有點和printf相似哦。第三個參數就是

// 提取出來的參數放置的真正位置。必須傳遞這個參數的地址。

//-------------------------------------------------------------------------

staticPyObject*Add(PyObject*self,PyObject*args)

{

       intx = 0 ;

       inty = 0;

       intz = 0;

       if(!PyArg_ParseTuple(args,"i|i", &x,  &y))

             returnNULL;

       z=x +y;

       returnPy_BuildValue("i",z);

       /*

            調用完以後咱們須要返回結果。這個結果是ctype或者是咱們本身定義的類型。

            必須把他轉換成PyObject,讓python認識。這個用Py_BuildValue來完成。他

            PyArg_ParseTuple的逆過程。他的第一個參數和PyArg_ParseTuple的第二個

            參數同樣,是個格式化符號。第三個參數是咱們須要轉換的參數。Py_BuildValue

            會把全部的返回只組裝成一個tutplepython

 

            若是對應的C函數沒有返回值(即返回值類型爲void),則應返回一個全局的None

            對象(Py_None),並將其引用計數增,以下所示:

            Py_INCREF(Py_None);

            returnPy_None;

      */

}

 

4、再加點功能

intcmd(constchar* arg)

{

       returnsystem(arg);

}

 

staticPyObject*ExecSystem(PyObject*self,PyObject*args)

{

       constchar*command;

       if(!PyArg_ParseTuple(args,"s", &command))

             returnNULL;

       intn =cmd(command);

       returnPy_BuildValue("i",n);

}

 

編譯

開編,編譯出來的PyExt.dll文件更名爲PyExt.pyd放入PythonC:\Python25\DLLs目錄就能夠全局使用了,若是你只想某個Python的工程,放在工程的相對路徑下面就能夠了。

 

使用

 

可能的問題

裏面的這些PyMODINIT_FUNC,與Python相關的宏和定義在哪裏呢?定義下#include<Python.h>就能夠了,可是定義了以後提示Python.h找不到仍是編譯不過怎麼辦?這說明你沒有安裝Python或者安裝了可是沒有把頭文件路徑引入Path環境變量,或者你把Pythoninclude目錄加入工程的附加包含目錄(Additional  IncludeDirectories,通常是C:\Python25\include這個目錄,其中C:\Python25Python的安裝目錄,按你機器的實際狀況配置)。

若是提示:Error  1    fatal error LNK1104:cannot open file 'python25_d.lib'      相似這樣的錯誤,通常多是沒有安裝Python的開發版本,不要緊,你使用Release編譯一下,若是還不行,就把C:\Python25\libs目錄加入工程的附加庫目錄(Additional  LibraryDirectories)。

 

參考文獻

[1] python官網http://www.python.org/

[2] C語言擴展python的功能https://www.ibm.com/developerworks/cn/linux/l-pythc/

[3] C++擴展和嵌入Pythonhttp://www.vckbase.com/index.php/wv/1258

[4] Python調用C/C++模塊http://blog.csdn.net/masefee/article/details/4750920

相關文章
相關標籤/搜索