1. 安裝Python開發(fā)包 由于需要訪問Python/C API,首先安裝Python開發(fā)包。 在Debian,Ubuntu或Linux Mint中: 在CentOS,Fedora或RHEL中: 安裝成功后,Python頭
成都創(chuàng)新互聯(lián)是專業(yè)的房縣網(wǎng)站建設(shè)公司,房縣接單;提供做網(wǎng)站、網(wǎng)站建設(shè),網(wǎng)頁設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行房縣網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來合作!
2. 初始化解釋器并設(shè)置路徑 C中嵌入Python的第一步是初始化Python解釋器,這可以用以下C函數(shù)完成。 初始化解釋器后,需要設(shè)置你的C程序中要導(dǎo)入的Python模塊
3. 數(shù)據(jù)轉(zhuǎn)換 C中嵌入Python最重要的方面之一是數(shù)據(jù)轉(zhuǎn)換。
原因分析:
先看幾個(gè)概念:
與外部庫連接
外部庫有兩種:?。?)靜態(tài)連接庫lib.a
(2)共享連接庫lib.so
共同點(diǎn):
.a, .so都是.o目標(biāo)文件的集合,這些目標(biāo)文件中含有一些函數(shù)的定義(機(jī)器碼),而這些函數(shù)將在連接時(shí)會(huì)被最終的可執(zhí)行文件用到。
區(qū)別:
靜態(tài)庫.a : 當(dāng)程序與靜態(tài)庫連接時(shí),庫中目標(biāo)文件所含的所有將被程序使用的函數(shù)的機(jī)器碼被copy到最終的可執(zhí)行文件中。
共享庫.so : 與共享庫連接的可執(zhí)行文件只包含它需要的函數(shù)的表,而不是所有的函數(shù)代碼,在程序執(zhí)行之前,那些需要的函數(shù)代碼被拷貝到內(nèi)存中,這樣就使可執(zhí)行文件比較 小,節(jié)省磁盤空間(更進(jìn)一步,操作系統(tǒng)使用虛擬內(nèi)存,使得一份共享庫駐留在內(nèi)存中被多個(gè)程序使用)。共享庫還有個(gè)優(yōu)點(diǎn):若庫本身被更新,不需要重新編譯與 它連接的源程序。
具體分析:
編譯器會(huì)給出上述錯(cuò)誤信息,這是因?yàn)閟qrt函數(shù)不能與外部數(shù)學(xué)庫"libm.a"相連。sqrt函數(shù)沒有在程序中定義,也不存在于默認(rèn)C庫 "libc.a"中,應(yīng)該顯式地選擇連接庫。上述出錯(cuò)信息中的"/tmp/ccdzoSZq.o"是gcc創(chuàng)造的臨時(shí)目標(biāo)文件,用作連接時(shí)用。
如何讓python調(diào)用C和C++代碼
安裝python后,會(huì)有一個(gè)chm格式的python手冊(cè)。要搞明白如何讓python調(diào)用C/C++代碼(也就是寫python的 extension),你需要征服手冊(cè)中的
Extending embedding厚厚的一章。在昨天花了一個(gè)小時(shí)看地頭暈?zāi)X脹,仍然不知道如何寫python的extension后,查閱了一些其他 書籍,最終在Python Programming On Win32書中找到了教程。
下面記錄一下如何在visual studio 2005中,寫一段C/C++的MessageBox代碼,然后提供后python調(diào)用,最后的結(jié)果當(dāng)然是顯示一個(gè)MessageBox.
1. 首先要明白的是,所謂的python擴(kuò)展(也就是你提供給python的c/c++代碼,不一定是c/c++代碼,可以是其他語言寫的代碼)是一個(gè) dll,并且這個(gè)dll放在本機(jī)python安裝目錄下的DLLs目錄下(譬如我機(jī)器上的路徑是:F:\Program Files\Python25\DLLs),假如我們接下來要寫的擴(kuò)展module名為mb,python調(diào)用的代碼為: import mb
mb.showMsg("Python's really amazing, I kindda love it!")
python怎么找到我們的mb模塊呢?就是上面說的,我們要生成一個(gè)mb.dll,然后拷貝到Dlls目錄下面,為了區(qū)別普通的dll和python專用擴(kuò)展的dll,我們的 mb.dll修改成mb.pyd(python dll)
2. 搭建環(huán)境,我們要使用python提供的c頭文件和lib庫來進(jìn)行擴(kuò)展的開發(fā)。 在vs 2005下點(diǎn)擊菜單 "工具"-"選項(xiàng)", 打開選項(xiàng)對(duì)話框,選擇"項(xiàng)目和解決方案-VC++目錄", 然后在右邊"顯示以下內(nèi)容的目錄"得comboBox上選擇"包含文件”,添加python的include目錄(我的機(jī)器上是"F:\Program
Files\Python25\include"),然后選擇庫文件,添加python的libs目錄(我的機(jī)器上是"F:\Program Files\Python25\libs")。
既然擴(kuò)展是一個(gè)dll,接下來我們要建立一個(gè)“動(dòng)態(tài)鏈接庫”工程,然后開始寫代碼:
#include python.h //python.h是包含python一些定義的頭文件,在python的include目錄下 /*
我的python版本是2.5, 因?yàn)榘惭bpython后它沒提供debug下的lib庫文件,因此你必須生成release版的dll,
想要生成dll版本的,你要到python官網(wǎng)上自己去下載python源代碼,當(dāng)然你可以繼續(xù)生成release版本的dll,但dll中包含調(diào)試信息
*/
#pragma comment(lib, "python25.lib")
//先不管
static PyObject* mb_showMsg(PyObject* self, PyObject *args); /*
如果你的擴(kuò)展是mb,那么必須實(shí)現(xiàn)一個(gè)initmb函數(shù),并且從dll中導(dǎo)出這個(gè)函數(shù),但我們?cè)趐ython中調(diào)用import mb時(shí),python會(huì)去dll里去調(diào)用
initmb函數(shù),這個(gè)函數(shù)告訴python我們有些什么函數(shù),該怎么告訴python我們有一個(gè)showMsg函數(shù)呢?下面詳解 */
//必須extern "C"下,這樣不會(huì)在C++編譯器里不會(huì)更改掉導(dǎo)出的函數(shù)名字,我第一次就犯了這樣的錯(cuò)誤
extern "C" __declspec(dllexport) void initmb() { /*
當(dāng)調(diào)用mb.showMsg("Python's really amazing, I kindda love it!")時(shí), 相當(dāng)于你告訴python我有一個(gè)showMsg函數(shù),我們?cè)趺锤嬖Vpython去調(diào)用我們dll里的mb_showMsg函數(shù)呢?技巧就是下面的方式, 定義一個(gè)字典數(shù)據(jù)結(jié)構(gòu),key = showMsg, value =mb_showMsg,METH_VARARGS是函數(shù)調(diào)用方式,仔細(xì)查手冊(cè)吧 */
static PyMethodDef mbMethods[] = { {"showMsg", mb_showMsg, METH_VARARGS},
{NULL, NULL, NULL} /*sentinel,哨兵,用來標(biāo)識(shí)結(jié)束*/ };
//告訴python我們的模塊名叫mb, 模塊包含的函數(shù)都在mbMethods字典里 PyObject *m = Py_InitModule("mb", mbMethods); } /*
接下來實(shí)現(xiàn)核心功能showMsg */
//第一個(gè)self參數(shù)我們用不著,具體查手冊(cè),第二個(gè)參數(shù)是python傳給我們的參數(shù),它是一個(gè)python的參數(shù)tuple
static PyObject* mb_showMsg(PyObject* self, PyObject *args) {
//我們的showMsg函數(shù)需要的是一個(gè)字符串參數(shù) const char* msg = NULL; /*
調(diào)用特殊參數(shù)解碼python傳遞給我們的參數(shù),s是string,我們傳遞接收參數(shù)的變量地址,
如果你的功能函數(shù)需要兩個(gè)參數(shù),在PyArg_parseTuple后面繼續(xù)添加接受參數(shù)的變量地址,
這個(gè)函數(shù)的原型是類似printf的不定參數(shù)的形式
PyAPI_FUNC(int) PyArg_ParseTuple(PyObject *, const char *, ...); */
if (!PyArg_ParseTuple(args, "s", msg)) return NULL;
//調(diào)用MB
int r = ::MessageBox(NULL, "hello", "Caption:Form C module", MB_ICONINFORMATION | MB_OK);
//返回值
return Py_BuildValue("i", r); }
將上面這段混雜著大量注釋的代碼拷貝到你的編輯器里,然后編譯生成mb.dll,修改后綴成mb.pyd,然后拷貝到python的DLLs目錄下,打開idle(python的交互程序),寫入代碼: import mb
mb.showMsg("Python's really amazing, I kindda love it!")
可以看到彈出來一個(gè)MessageBox。
用c語言編寫一個(gè)動(dòng)態(tài)庫,提供兩個(gè)函數(shù),兩個(gè)數(shù)的整形求和,兩個(gè)浮點(diǎn)數(shù)的求和。取名為mylib.c。
將c函數(shù)文件編譯成so動(dòng)態(tài)庫。運(yùn)行g(shù)cc mylib.c -fPIC -shared -o libtest.so命令,在目錄下可以看到生成的庫文件libtest.so。
Python調(diào)用so庫文件。首先導(dǎo)入ctypes,其次用CDLL加載so文件,最后調(diào)用對(duì)應(yīng)的函數(shù)。將python代碼保存到pydemo.py中。
執(zhí)行python pydemo.py查看運(yùn)行結(jié)果。
眾多python培訓(xùn)視頻,盡在python學(xué)習(xí)網(wǎng),歡迎在線學(xué)習(xí)!
是因?yàn)槟愕哪K的路徑不對(duì),必須先指定路徑
PyObject *sys = PyImport_ImportModule("sys");
PyObject *path = PyObject_GetAttrString(sys, "path");
PyList_Append(path, PyString_FromString("."));
在C/C++中嵌入Python也比較簡(jiǎn)單,首先需要在VC中添加Python的include文件目錄和lib文件目錄:
VC6.0下,打開 tools-options-directories-show directories for,將Python安裝目錄下的inlude目錄添加到inlude files項(xiàng)中,將libs目錄添加到library files項(xiàng)中。
VC2005下,打開tools-options-項(xiàng)目和解決方案-VC++目錄,然后做相同工作。
代碼如下:
//在debug下執(zhí)行出錯(cuò),“無法找到python31_d.lib文件”,后查到原因是:在debug下生成必須要有python31_d.lib文件,否則只能在release下生成
#include python.h
int main()
{
Py_Initialize();
PyRun_SimpleString("Print 'hi, python!'");
Py_Finalize();
return 0;
}
Py_Initialize函數(shù)原型是:void Py_Initialize(),在嵌入Python腳本時(shí)必須使用該函數(shù),它初始化Python解釋器,在使用其他的Python/C API之前必須先調(diào)用該函數(shù)??梢允褂肞y_IsInitialized函數(shù)判斷是否初始化成功,成功返回True。
PyRun_SimpleString函數(shù)原型是int PyRun_SimpleString(const char *command),用來執(zhí)行一段Python代碼。注意:是否需要維持語句間的縮進(jìn)呢?
Py_Finalize函數(shù)原型是void Py_Finalize(),用于關(guān)閉Python解釋器,釋放解釋器所占用的資源。
PyRun_SimpleFile函數(shù)可以用來運(yùn)行".py"腳本文件,函數(shù)原型如下:
int PyRun_SimpleFile(FILE *fp, const char *filename);
其 中fp是打開的文件指針,filename是要運(yùn)行的python腳本文件名。但是由于該函數(shù)官方發(fā)布的是由visual studio 2003.NET編譯的,如果使用其他版本的編譯器,F(xiàn)ILE定義可能由于版本原因?qū)е卤罎?。同時(shí),為簡(jiǎn)便起見可以使用如下方式來代替該函數(shù):
PyRun_SimpleString("execfile(‘file.py’)"); //使用execfile來運(yùn)行python文件
Py_BuildValue()用于對(duì)數(shù)字和字符串進(jìn)行轉(zhuǎn)換處理,變成Python中相應(yīng)的數(shù)據(jù)類型(在C語言中,所有Python類型都被聲明為PyObject類型),函數(shù)原型如下:
PyObject *Py_BuildValue(const char *format, …..);
PyString_String()用于將PyObject*類型的變量轉(zhuǎn)換成C語言可以處理的char*型,具體原型如下:
char* PyString_String(PyObject *p);
列表操作函數(shù):
PyObject * PyList_New(Py_ssize_t len);
int PyList_SetItem(PyObject *list, Py_ssize_t index, PyObject *item);
PyObject * PyList_GetItem(PyObject *list, Py_ssize_t index);
int PyList_Append(PyObject *list, PyObject *item);
int PyList_Sort(PyObject *list);
int PyList_Reverse(PyObject *list);
Py_ssize_t PyList_Size(PyObject *list);
元組操作函數(shù):
int PyTuple_New(Py_ssize_t len);
int PyTuple_SetItem(PyObject *p, Py_ssize_t pos, PyObject *o);
PyObject * PyTuple_GetItem(PyObject *p, Py_ssize_t pos);
int _PyTuple_Resize(PyObject **p, Py_ssize_t newsize); //注意是**指針
字典操作函數(shù):
PyObject * PyDict_New();
int PyDict_SetItem(PyObject *p, PyObject *key, PyObject *val);
int PyDict_SetItemString(PyObject *p, const char *key, PyObject *val);
PyObject* PyDict_GetItem(PyObject *p, PyObject *key);
PyObject* PyDict_GetItemString(PyObject *p, const char *key);
//與PyDict_SetItemString對(duì)應(yīng)
int PyDict_DelItem(PyObject *p, PyObject *key);
int PyDict_DelItemString(PyObject *p, char *key);
//與PyDict_SetItemString對(duì)應(yīng)
int PyDict_Next(PyObject *p, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue);
PyObject* PyDict_Items(PyObject *p);
PyObject* PyDict_keys(PyObject *p);
PyObject* PyDict_Values(PyObject *p);
在C/C++中使用Python對(duì)象應(yīng)正確地處理引用計(jì)數(shù)問題,否則容易導(dǎo)致內(nèi)存泄漏。當(dāng)使用Python/C API中的函數(shù)創(chuàng)建列表、元組、字典等后,在對(duì)其完成操作后應(yīng)該使用Py_CLEAR()和Py_DECREF()等宏來銷毀這些對(duì)象。原型如下:
void Py_CLEAR(PyObject *o);
void Py_DECREF(PyObject *o);
其中,對(duì)于Py_CLEAR函數(shù),參數(shù)可以為NULL指針,表示不進(jìn)行任何操作,但是Py_DECREF函數(shù)不能為NULL指針,否則導(dǎo)致錯(cuò)誤。
使用PyImport_Import()函數(shù)可以在C中導(dǎo)入Python模塊,返回一個(gè)模塊對(duì)象。函數(shù)原型為:
PyObject* PyImport_Import(PyObject *name);
PyModule_GetDict()函數(shù)可以獲得Python模塊中的函數(shù)列表,返回一個(gè)字典,字典中的關(guān)鍵字為函數(shù)名,值為函數(shù)的調(diào)用地址。原型如下:
PyObject* PyModule_GetDict(PyObject *module);
使用PyObject_CallObject()函數(shù)和PyObject_CallFunction()函數(shù)可以在C中調(diào)用Python中的函數(shù),原型如下:
PyObject* PyObject_CallObject(PyObject *callable_object, PyObject *args);
//args是元組形式
PyObject* PyObject_CallFunction(PyObject *callable, char *format, ……);
//format是類似”iss”這樣的參數(shù)類型,后面是指定參數(shù)
可以使用PyCallable_Check(func)來判斷是否可以調(diào)用函數(shù),可以則返回True。