Ⅰ 如何讓python調用C和C++代碼
要搞明白如何讓python調用C/C++代碼(也就是寫python的extension),你需要征服手冊中的<<Extending && embedding>>厚厚的一章。在昨天花了一個小時看地頭暈腦脹,仍然不知道如何寫python的extension後,查閱了一些其他書籍,最終在<<Python Programming On Win32>>書中找到了教程。
1. 首先要明白的是,所謂的python擴展(也就是你提供給python的c/c++代碼,不一定是c/c++代碼,可以是其他語言寫的代碼)是一個dll,並且這個dll放在本機python安裝目錄下的DLLs目錄下(譬如我機器上的路徑是:F:/Program Files/Python25/DLLs),假如我們接下來要寫的擴展mole名為mb,python調用的代碼為:import mbmb.showMsg("Python's really amazing, I kindda love it!")
2. 搭建環境,我們要使用python提供的c頭文件和lib庫來進行擴展的開發。
在vs 2005下點擊菜單 "工具"->"選項", 打開選項對話框,選擇"項目和解決方案->VC++目錄", 然後在右邊"顯示以下內容的目錄"得comboBox上選擇"包含文件」,添加python的include目錄(我的機器上是"F:/Program Files/Python25/include"),然後選擇庫文件,添加python的libs目錄(我的機器上是"F:/Program Files/Python25/libs")。
既然擴展是一個dll,接下來我們要建立一個「動態鏈接庫」工程,然後開始寫代碼:
#include <python.h> //python.h是包含python一些定義的頭文件,在python的include目錄下/*我的python版本是2.5, 因為安裝python後它沒提供debug下的lib庫文件,因此你必須生成release版的dll,
想要生成dll版本的,你要到python官網上自己去下載python源代碼,當然你可以繼續生成release版本的dll,但dll中包含調試信息*/#pragma comment(lib, "python25.lib")//先不管static PyObject* mb_showMsg(PyObject* self, PyObject *args);/*如果你的擴展是mb,那麼必須實現一個initmb函數,並且從dll中導出這個函數,但我們在python中調用import mb時,python會去dll里去調用
extern "C" __declspec(dllexport) void initmb(){/*當調用mb.showMsg("Python's really amazing, I kindda love it!")時, 相當於你告訴python我有一個showMsg函數,我們怎麼告訴python去調用我們dll里的mb_showMsg函數呢?技巧就是下面的方式,定義一個字典數據結構,key => showMsg, value =>mb_showMsg,METH_VARARGS是函數調用方式,仔細查手冊吧*/static PyMethodDef mbMethods[] = {
{"showMsg", mb_showMsg, METH_VARARGS},
{NULL, NULL, NULL} /*sentinel,哨兵,用來標識結束*/};//告訴python我們的模塊名叫mb, 模塊包含的函數都在mbMethods字典里
PyObject *m = Py_InitMole("mb", mbMethods);}/*接下來實現核心功能showMsg*///第一個self參數我們用不著,具體查手冊,第二個參數是python傳給我們的參數,它是一個python的參數tuple
static PyObject* mb_showMsg(PyObject* self, PyObject *args){//我們的showMsg函數需要的是一個字元串參數
const char* msg = NULL;/*調用特殊參數解碼python傳遞給我們的參數,s是string,我們傳遞接收參數的變數地址,
如果你的功能函數需要兩個參數,在PyArg_parseTuple後面繼續添加接受參數的變數地址,
這個函數的原型是類似printf的不定參數的形式
PyAPI_FUNC(int) PyArg_ParseTuple(PyObject *, const char *, ...);*/if (!PyArg_ParseTuple(args, "s", &msg))
return NULL;//調用MBint r = ::MessageBox(NULL, "hello", "Caption:Form C mole", MB_ICONINFORMATION | MB_OK);//返回值return Py_BuildValue("i", r);}將上面這段混雜著大量注釋的代碼拷貝到你的編輯器里,然後編譯生成mb.dll,修改後綴成mb.pyd,然後拷貝到python的DLLs目錄下,打開idle(python的交互程序),寫入代碼:import mbmb.showMsg("Python's really amazing, I kindda love it!")
Ⅱ 如何用Python封裝C語言的字元串處理函數
在C語言中,字元串處理是每天都要面對的問題。我們都知道C語言中其實並沒有一種原生的字元串類型,『字元串』在C語言里只是一種特殊的以''結尾的字元數組。因此,如何將C語言與更高層次的Python語言在『字元串』處理這個問題上對接是一個有難度的問題。所幸有swig這種強大的工具。
如何封裝一個函數,它修改參數字元串的內容
假如有這樣一個C語言的函數,
<!-- lang: cpp -->
void FillZero(char* pc,size_t * piLen)
{
size_t i=0;
while(i++<*piLen/2 )
*pc++ = '0';
*pc = 0;
*piLen = i+1;
}
這個函數的功能是把字元串變成n個0。不過我們更關注函數的形式。這樣的函數,表面上看char* pc是函數的參數,可是實際上它才是函數的返回值和執行的結果。piLen這個參數既是pc的最大長度,也是新的字元串的長度。我們直接用python封裝,看看運行結果。
Type "help", "right", "credits" or "license" for more information.
>>> import cchar
>>> s='123456'
>>> cchar.FillZero(s,6)
Traceback (most recent call last):
File "<stdin>", line 1, in <mole>
TypeError: in method 'FillZero', argument 2 of type 'size_t *'
結果差強人意,不是我們想要得到的結果。函數的第二個參數為size_t* 我們很難用python來表示,而且python中也不存在既是輸入,也是輸出的參數。
swig有一個標准庫,其中有一個cstring.i文件就是用來解決C語言字元串類型的問題。
我們在.i文件中加入這樣幾行
<!-- lang: cpp -->
%include "cstring.i"
%cstring_output_withsize(char* pc,size_t* pi)
void FillZero(char* pc, size_t* pi);
然後運行看結果
Type "help", "right", "credits" or "license" for more information.
>>> import cchar
>>> cchar.FillZero(10)
'00000\x00'
>>> s=cchar.FillZero(10)
>>> print s
00000
我們看函數的變化。首先在python里, FillZero變成了只有一個參數的函數。然後函數的返回值變成了一個字元串。其實cstring_output_size其實是一個宏,通過這個宏的定義改變了函數的形式,直接在Python中得到我們想要的結果。
其實類似cstring_output_size的宏還有好幾個,我列舉一下:
cstring_output_allocate(char *s,free($1));
第一個參數是指向字元串地址的指針,第二個參數為釋放空間的方法。
大家考慮這一下這樣的函數:
void foo(char* & s)
{
s = (char*)malloc(10);
memcpy(s,"123456789",9);
}
s這個參數表面上看是輸入,實際上是函數真正的輸出。 函數中真正改變的東西是char&s指向的字元串的值。而且char&這個類型,
python或者其他腳本語言里應該都沒有對應的類型。那麼我們用cstring_output_allocate將這個函數轉換成另外一個形式的python或者其他腳本語言的函數。轉換後的函數其實是這樣的,以python為例str
foo()。
<!-- lang: cpp -->
%mole a
%include "cstring.i"
%{
void foo(char*& s);
%}
%cstring_output_allocate(char *&s, free(*$1));
void foo(char *&s);
在python中的調用:
<!-- lang: python -->
>>> import a
>>> a.foo()
'123456789'
>>>
cstring_output_maxsize(char *path, int maxpath);
第一個參數也是可以改變的字元串首地址,第二個參數為字元串的最大長度。在Python中調用的時候,只有maxpath這個參數,返回字元串。
cstring_output_allocate(char *s, free($1));
第一個參數為指向字元串首地址的指針,第二個參數為釋放指針的方法。這個宏主要是封裝一種直接在函數內部malloc空間的函數。在Python中調用時沒有參數,直接返回字元串。
cstring_output_allocate_size(char *s, int slen, free(*$1));
這個相當於前面兩個函數的組合。在函數內部malloc空間,然後將字元串長度通過slen返回。其實在調用的時候非常簡單,沒有參數,直接返回字元串。
如何處理c++的std::string
std::string是C++標准類庫STL中常見的類。在平時工作中大家肯定是沒少用。在python中如何封裝std::string? swig提供了標准庫
例如函數:
<!-- lang: cpp -->
string Repeat(const string& s)
{
return s+s;
}
只要在swig中加入這樣幾行:
<!-- lang: cpp -->
%include "std_string.i"
using namespace std;
string Repeat(const string& s);
運行結果:
Python 2.6.6 (r266:84292, Dec 27 2010, 00:02:40)
[GCC 4.4.5] on linux2
Type "help", "right", "credits" or "license" for more information.
>>> import cchar
>>> cchar.Repeat('123')
'123123'
使用起來很方便,但需要注意的是,假如函數的參數的內容是可以被修改,就不能用這種方式封裝。
例如:
<!-- lang: cpp -->
void repeat(string s)
{
s+=s;
}
這樣的函數直接使用 'std_string.i' 就是無效的。遇到這種函數,只能用C語言封裝成 void repeat(chars, int maxsize), 再用swig調用 'cstring_output_withsize' 這個宏再封裝一次了。
Ⅲ 怎樣把Python代碼嵌入到C程序
這篇文章主要介紹了將Python代碼嵌入C++程序進行編寫的實例,盡管通常還是Python代碼中調用C++程序的情況較多...需要的朋友可以參考下
把python嵌入的C++裡面需要做一些步驟
安裝python程序,這樣才能使用python的頭文件和庫
在我們寫的源文件中增加「Python.h」頭文件,並且鏈入「python**.lib」庫(還沒搞清楚這個庫時靜態庫還是導出庫,需要搞清楚)
掌握和了解一些python的C語言api,以便在我們的c++程序中使用
常用的一些C API函數
在了解下面的函數之前有必要了解一下**PyObject***指針,python裡面幾乎所有的對象都是使用這個指針來指示的。
Py_Initialize()&&Py_Finalize()
在調用任何python的c函數之前需要調用的函數,「Py_Initialize」是用來初始化python模塊的,推測是載入初始化載入dll的。對應的在使用python模塊之後用「Py_Finalize」來釋放模塊。
PyImport_ImportMole()
用來載入一個python模塊,這個模塊就是一般的python文件。這里需要注意的是,在載入這個模塊的時候會執行模塊裡面所有可以執行的語句。包括import導入語句和在函數體之外的所有語句
PyObject_GetAttrString()
返回模塊裡面的函數
Py_BuildValue()
建立一個參數元組,一般都是用這個函數來建立元組,然後將這個元組作為參數傳遞給python裡面的函數。
PyEval_CallObject()
調用函數,並把「Py_BuildValue」建立的元組作為參數傳遞給被調用的函數
源碼實例
下面的實例是在c++代碼中調用Python的函數,傳遞參數並且獲取返回值
test.cpp代碼
[cpp]view plain
#include<iostream>
#include<Python.h>
usingnamespacestd;
intmain(intargc,char*argv[])
{
Py_Initialize();//初始化
PyObject*pMole=NULL;
PyObject*pFunc=NULL;
PyObject*pParam=NULL;
PyObject*pResult=NULL;
constchar*pBuffer=NULL;
intiBufferSize=0;
pMole=PyImport_ImportMole(「test_python");
if(!pMole)
{
cout<<"getmolefailed!"<<endl;
exit(0);
}
pFunc=PyObject_GetAttrString(pMole,"main");
if(!pFunc)
{
cout<<"getfuncfailed!"<<endl;
cout<<int(pFunc)<<endl;
exit(0);
}
pParam=Py_BuildValue("(s)","HEHEHE");
pResult=PyEval_CallObject(pFunc,pParam);
if(pResult)
{
if(PyArg_Parse(pResult,"(si)",&pBuffer,iBufferSize))
{
cout<<pBuffer<<endl;
cout<<iBufferSize<<endl;
}
}
Py_DECREF(pParam);
Py_DECREF(pFunc);
Py_Finalize();
//cout<<"hello"<<endl;
return0;
}
test_python.py代碼
[py]view plain
defmain(szString):
return("hello",5)
Ⅳ .py文件調用.cpp文件 運行.py文件時,輸出.cpp文件的結果,也就是說.py文件調用.cpp文件,怎麼做啊啊啊啊
您好,您可以試試:
a=1
b=2
print a+b
#!/usr/bin/env python
import os
os.system( "python ./a.py" )