你試過C語言和Python一起混合編程嗎?兩者相加不是已經(jīng)無敵了!
C語言是編程語言的祖母,但是隨著一代一代的編程語言長大,所以祖母也是會拍在沙灘上的,很多小小伙伴應(yīng)該都會學(xué)過或者了解C語言,因為軟件系的會教嘛,但是Python我想很多人都沒學(xué)過,下面小編給大家介紹下,C語言和Python一起混合編程會產(chǎn)生什么不一樣的火花吧!
在Mac OS X 下的編譯命令同上
產(chǎn)生可執(zhí)行文件后,直接運行,結(jié)果為輸出
1 2 |
Hello Python! |
Python庫函數(shù)PyRun_SimpleString可以執(zhí)行字符串形式的Python代碼。
雖然非常簡單,但這段代碼除了能用C語言動態(tài)生成一些Python代碼之外,并沒有什么用處。我們需要的是C語言的數(shù)據(jù)結(jié)構(gòu)能夠和Python交互。
下面舉個例子,比如說,有一天我們用Python寫了一個功能特別強大的函數(shù):
從上述代碼可以窺見Python內(nèi)部運行的方式:
-
所有Python元素,module、function、tuple、string等等,實際上都是PyObject。C語言里操縱它們,一律使用PyObject *。
-
Python的類型與C語言類型可以相互轉(zhuǎn)換。Python類型XXX轉(zhuǎn)換為C語言類型YYY要使用PyXXXAsYYY函數(shù);C類型YYY轉(zhuǎn)換為Python類型XXX要使用PyXXXFromYYY函數(shù)。
-
也可以創(chuàng)建Python類型的變量,使用PyXXX_New可以創(chuàng)建類型為XXX的變量。
-
若a是Tuple,則a[i] = b對應(yīng)于 PyTupleSetItem(a,i,b),有理由相信還有一個函數(shù)PyTupleGetItem完成取得某一項的值。
-
不僅Python語言很優(yōu)雅,Python的庫函數(shù)API也非常優(yōu)雅。
現(xiàn)在我們得到了一個C語言的函數(shù)了,可以寫一個main測試它
編譯的方式就用本節(jié)開頭使用的方法。
在Linux/Mac OSX運行此示例之前,可能先需要設(shè)置環(huán)境變量:
bash:
1 2 |
export PYTHONPATH=.:$PYTHONPATH |
csh:
1 2 |
setenv PYTHONPATH.:$PYTHONPATH |
2 Python 調(diào)用 C/C++(基礎(chǔ)篇)
這種做法稱為Python擴展。
比如說,我們有一個功能強大的C函數(shù)
除了功能強大的函數(shù)great_function外,這個文件中還有以下部分:
-
包裹函數(shù)greatfunction。它負責(zé)將Python的參數(shù)轉(zhuǎn)化為C的參數(shù)(PyArgParseTuple),調(diào)用實際的greatfunction,并處理great_function的返回值,最終返回給Python環(huán)境。
-
導(dǎo)出表GreateModuleMethods。它負責(zé)告訴Python這個模塊里有哪些函數(shù)可以被Python調(diào)用。導(dǎo)出表的名字可以隨便起,每一項有4個參數(shù):***個參數(shù)是提供給Python環(huán)境的函數(shù)名稱,第二個參數(shù)是greatfunction,即包裹函數(shù)。第三個參數(shù)的含義是參數(shù)變長,第四個參數(shù)是一個說明性的字符串。導(dǎo)出表總是以{NULL, NULL, 0, NULL}結(jié)束。
-
導(dǎo)出函數(shù)initgreat_module。這個的名字不是任取的,是你的module名稱添加前綴init。導(dǎo)出函數(shù)中將模塊名稱與導(dǎo)出表進行連接。
在Windows下面,在Visual Studio命令提示符下編譯這個文件的命令是
本部分參考資料
-
《Python源碼剖析-深度探索動態(tài)語言核心技術(shù)》是系統(tǒng)介紹CPython實現(xiàn)以及運行原理的優(yōu)秀教程。
-
Python 官方文檔的這一章詳細介紹了C/C++與Python的雙向互動Extending and Embedding the Python Interpreter _ _
-
關(guān)于編譯環(huán)境,本文所述方法僅為出示原理所用。規(guī)范的方式如下:3. Building C and C++ Extensions with distutils _ _
-
作為字典使用的官方參考文檔Python/C API Reference Manual _ _
這其中有非Python關(guān)鍵字cdef和public。這些關(guān)鍵字屬于Cython。由于我們需要在C語言中使用“編譯好的Python代碼”,所以得讓great_function從外面變得可見,方法就以“public”修飾。而cdef類似于Python的def,只有使用cdef才可以使用Cython的關(guān)鍵字public。
這個函數(shù)中其他的部分與正常的Python代碼是一樣的。
接下來編譯 great_module.pyx
編譯命令和***部分相同:
在Windows下編譯命令為
在Visual Studio命令提示符下編譯:
1 2 |
cl/LD dllmain.cgreat_module.c-IC:Python27includeC:Python27libspython27.lib |
會得到一個dllmain.dll。我們在Excel里面使用它,沒錯,傳說中的Excel與Python混合編程:
參考資料:Cython的官方文檔,質(zhì)量非常高:
接下來使用SWIG將這個配置文件編譯為所謂Python Module Wrapper
1 2 |
swig-python mymodule.i |
得到一個 mymodule_wrap.c和一個mymodule.py。把它編譯為Python擴展:
Windows:
1 2 |
cl/LD mymodule_wrap.c/o_mymodule.pyd-IC:Python27includeC:Python27libspython27.lib |
Linux:
1 2 |
gcc-fPIC-shared mymodule_wrap.c-o_mymodule.so-I/usr/include/python2.7/-lpython2.7 |
注意輸出文件名前面要加一個下劃線。
現(xiàn)在可以立即在Python下使用這個module了:
換句話說,SWIG自動完成了諸如Python類型轉(zhuǎn)換、module初始化、導(dǎo)出代碼表生成的諸多工作。
對于C++,SWIG也可以應(yīng)對。例如以下代碼有C++類的定義:
寫在***:
由于CPython自身的結(jié)構(gòu)設(shè)計合理,使得Python的C/C++擴展非常容易。如果打算快速完成任務(wù),Cython(C/C++調(diào)用Python)和SWIG(Python調(diào)用C/C++)是很不錯的選擇。但是,一旦涉及到比較復(fù)雜的轉(zhuǎn)換任務(wù),無論是繼續(xù)使用Cython還是SWIG,仍然需要學(xué)習(xí)Python源代碼。