Python是解釋性語言, 底層就是用c實現(xiàn)的, 所以用python調(diào)用C是很容易的, 下面就總結(jié)一下各種調(diào)用的方法, 給出例子, 所有例子都在ubuntu9.10, python2.6下試過
孟州ssl適用于網(wǎng)站、小程序/APP、API接口等需要進行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18980820575(備注:SSL證書合作)期待與您的合作!
1. Python 調(diào)用 C (base)
想在python中調(diào)用c函數(shù), 如這兒的fact
#include Python.h
int fact(int n)
{
if (n = 1)
return 1;
else
return n * fact(n - 1);
}
PyObject* wrap_fact(PyObject* self, PyObject* args)
{
int n, result;
if (! PyArg_ParseTuple(args, "i:fact", n))
return NULL;
result = fact(n);
return Py_BuildValue("i", result);
}
static PyMethodDef exampleMethods[] =
{
{"fact", wrap_fact, METH_VARARGS, "Caculate N!"},
{NULL, NULL}
};
void initexample()
{
PyObject* m;
m = Py_InitModule("example", exampleMethods);
}
把這段代碼存為wrapper.c, 編成so庫,
gcc -fPIC wrapper.c -o example.so -shared -I/usr/include/python2.6 -I/usr/lib/python2.6/config
然后在有此so庫的目錄, 進入python, 可以如下使用
import example
example.fact(4)
2. Python 調(diào)用 C++ (base)
在python中調(diào)用C++類成員函數(shù), 如下調(diào)用TestFact類中的fact函數(shù),
#include Python.h
class TestFact{
public:
TestFact(){};
~TestFact(){};
int fact(int n);
};
int TestFact::fact(int n)
{
if (n = 1)
return 1;
else
return n * (n - 1);
}
int fact(int n)
{
TestFact t;
return t.fact(n);
}
PyObject* wrap_fact(PyObject* self, PyObject* args)
{
int n, result;
if (! PyArg_ParseTuple(args, "i:fact", n))
return NULL;
result = fact(n);
return Py_BuildValue("i", result);
}
static PyMethodDef exampleMethods[] =
{
{"fact", wrap_fact, METH_VARARGS, "Caculate N!"},
{NULL, NULL}
};
extern "C" //不加會導致找不到initexample
void initexample()
{
PyObject* m;
m = Py_InitModule("example", exampleMethods);
}
把這段代碼存為wrapper.cpp, 編成so庫,
g++ -fPIC wrapper.cpp -o example.so -shared -I/usr/include/python2.6 -I/usr/lib/python2.6/config
然后在有此so庫的目錄, 進入python, 可以如下使用
import example
example.fact(4)
3. Python 調(diào)用 C++ (Boost.Python)
Boost庫是非常強大的庫, 其中的python庫可以用來封裝c++被python調(diào)用, 功能比較強大, 不但可以封裝函數(shù)還能封裝類, 類成員.
首先在ubuntu下安裝boost.python, apt-get install libboost-python-dev
#include boost/python.hpp
char const* greet()
{
return "hello, world";
}
BOOST_PYTHON_MODULE(hello)
{
using namespace boost::python;
def("greet", greet);
}
把代碼存為hello.cpp, 編譯成so庫
g++ hello.cpp -o hello.so -shared -I/usr/include/python2.5 -I/usr/lib/python2.5/config -lboost_python-gcc42-mt-1_34_1
此處python路徑設(shè)為你的python路徑, 并且必須加-lboost_python-gcc42-mt-1_34_1, 這個庫名不一定是這個, 去/user/lib查
然后在有此so庫的目錄, 進入python, 可以如下使用
import hello
hello.greet()
'hello, world'
4. python 調(diào)用 c++ (ctypes)
ctypes is an advanced ffi (Foreign Function Interface) package for Python 2.3 and higher. In Python 2.5 it is already included.
ctypes allows to call functions in dlls/shared libraries and has extensive facilities to create, access and manipulate simple and complicated C data types in Python - in other words: wrap libraries in pure Python. It is even possible to implement C callback functions in pure Python.
#include Python.h
class TestFact{
public:
TestFact(){};
~TestFact(){};
int fact(int n);
};
int TestFact::fact(int n)
{
if (n = 1)
return 1;
else
return n * (n - 1);
}
extern "C"
int fact(int n)
{
TestFact t;
return t.fact(n);
}
將代碼存為wrapper.cpp不用寫python接口封裝, 直接編譯成so庫,
g++ -fPIC wrapper.cpp -o example.so -shared -I/usr/include/python2.6 -I/usr/lib/python2.6/config
進入python, 可以如下使用
import ctypes
pdll = ctypes.CDLL('/home/ubuntu/tmp/example.so')
pdll.fact(4)
12
下面是一個例子:
首先是python的一個簡單函數(shù)
class Hello:
def __init__(self, x):
self.a = x
def print(self, x=None):
print(x)
def xprint():
print("hello world")
if __name__ == "__main__":
xprint()
h = Hello(5)
h.print()1
下面是C語言
#include python3.4m/Python.h
#include stdio.h
#include stdlib.h
#include string.h
int main()
{
Py_Initialize();
// 將當前目錄加入sys.path
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");
// 導入hello.py模塊
PyObject *pmodule = PyImport_ImportModule("hello");
// 獲得函數(shù)xprint對象,并調(diào)用,輸出“hello world\n”
PyObject *pfunc = PyObject_GetAttrString(pmodule, "xprint");
PyObject_CallFunction(pfunc, NULL);
// 獲得類Hello并生成實例pinstance,并調(diào)用print成員函數(shù),輸出“5 6\n”
PyObject *pclass = PyObject_GetAttrString(pmodule, "Hello");
PyObject *arg = Py_BuildValue("(i)", 5);
PyObject *pinstance = PyObject_Call(pclass, arg, NULL);
PyObject_CallMethod(pinstance, "print", "i", 6);
Py_Finalize();
return 0;
}
編譯命令如下:
gcc pyapi.c -lpython3.4m -o pyapi
步驟1:安裝Python開發(fā)包
由于需要訪問Python/C API,首先安裝Python開發(fā)包。
在Debian,Ubuntu或Linux Mint中:
在CentOS,F(xiàn)edora或RHEL中:
安裝成功后,Python頭文件在/usr/include/python2.7。根據(jù)Linux發(fā)行版的不同,確切的路徑可能是不相同的。例如,CentOS 6中是/usr/include/python2.6。
步驟2:初始化解釋器并設(shè)置路徑
C中嵌入Python的第一步是初始化Python解釋器,這可以用以下C函數(shù)完成。
初始化解釋器后,需要設(shè)置你的C程序中要導入的Python模塊的路徑。例如,比如你的Python模塊位于/usr/local/modules。然后使用以下C函數(shù)調(diào)用來設(shè)置路徑。
步驟3:數(shù)據(jù)轉(zhuǎn)換
C中嵌入Python最重要的方面之一是數(shù)據(jù)轉(zhuǎn)換。從C中傳遞數(shù)據(jù)到Python函數(shù),需要首先將數(shù)據(jù)從C數(shù)據(jù)類型轉(zhuǎn)換到Python數(shù)據(jù)類型。Python/C API提供各種函數(shù)來實現(xiàn)這。例如,轉(zhuǎn)換C字符串到Python字符串,使用PyString_FromString函數(shù)。
另外一個類似函數(shù)PyInt_FromLong,將C中l(wèi)ong數(shù)據(jù)類型轉(zhuǎn)換為Python int。每個Python/C API函數(shù)返回一個PyObject類型的引用。
步驟4:定義一個Python模塊
當你想嵌入Python代碼到另一種語言如C,該代碼需要被寫成Python模塊,然后用另一種語言“導入”。所以讓我們來看看如何在C中導入Python模塊。
為了進行說明,我們實現(xiàn)一個簡單的Python模塊例子如下:
以上的Python函數(shù)有一個字符串作為參數(shù)并返回兩個重復的字符串。例如,如果輸入字符串是“cyberpersons”,該函數(shù)返回'cyberpersonscyberpersons'。此模塊文件命名為“printData.py”并將它放在前面聲明的Python模塊目錄中(/usr/local/modules)。
步驟5:加載一個Python模塊
現(xiàn)在你已經(jīng)定義了Python模塊,是時候在C程序中加載它了。導入模塊的C代碼看起來像這樣:
步驟6:構(gòu)建函數(shù)的參數(shù)
當加載一個模塊時,可以調(diào)用模塊中定義的Python函數(shù)。通常,我們需要傳遞一個或多個參數(shù)到一個Python函數(shù)。我們必須構(gòu)建一個Python元組對象,它包括Python函數(shù)中的參數(shù)。
在我們的例子中,printData函數(shù)定義帶一個參數(shù)的模塊。因此,我們構(gòu)建一個大小是一的Python元組對象如下。我們可以使用PyTuple_SetItem設(shè)置元組對象的每個項。
我們已經(jīng)成功構(gòu)建一個參數(shù)傳遞到函數(shù)調(diào)用,是時候從C程序調(diào)用python函數(shù)了。
步驟7:調(diào)用Python函數(shù)
一旦成功創(chuàng)建Python元組對象作為函數(shù)參數(shù),我們可以調(diào)用一個帶參數(shù)的Python函數(shù)。為此,通過使用PyObject_GetAttrString首先獲得模塊中定義的函數(shù)的引用,然后使用PyObject_CallObject調(diào)用該函數(shù)。例如:
步驟8:錯誤檢查
避免運行時錯誤的常見方法是檢查函數(shù)的返回值并根據(jù)返回值采取適當?shù)男袆?。類似于C程序中的全局變量errno,Python/C API提供一個全局指示符,它報告最后發(fā)生的錯誤。當Python/C API函數(shù)失敗,全局指示符設(shè)置為指示錯誤,并且PyErr_Print可以用于顯示相應(yīng)的人類可讀的trackback。例如:
在你的應(yīng)用程序中,你可以輕松地將各種錯誤檢查。
這里是完整的C程序,它如本教程描述的嵌入Python代碼。
步驟9:編譯和執(zhí)行
保存以上代碼到finalCode.c,并且鏈接Python庫(-lpython2.7)編譯該代碼。根據(jù)發(fā)行版的不同,可能使用不同的版本(例如,-lpython2.6)。
C/C++ 調(diào)用 Python(基礎(chǔ)篇)
Python 本身就是一個C庫。你所看到的可執(zhí)行體python只不過是個stub。真正的python實體在動態(tài)鏈接庫里實現(xiàn),在Windows平臺上,這個文件位于 %SystemRoot%\System32\python27.dll。
你也可以在自己的程序中調(diào)用Python,看起來非常容易:
//my_python.c
#include Python.h
int main(int argc, char *argv[])
{
Py_SetProgramName(argv[0]);
Py_Initialize();
PyRun_SimpleString("print 'Hello Python!'\n");
Py_Finalize();
return 0;
}
在Windows平臺下,打開Visual Studio命令提示符,編譯命令為
cl my_python.c -IC:\Python27\include C:\Python27\libs\python27.lib
在Linux下編譯命令為
gcc my_python.c -o my_python -I/usr/include/python2.7/ -lpython2.7
在Mac OS X 下的編譯命令同上
產(chǎn)生可執(zhí)行文件后,直接運行,結(jié)果為輸出
Hello Python!
Python庫函數(shù)PyRun_SimpleString可以執(zhí)行字符串形式的Python代碼。
雖然非常簡單,但這段代碼除了能用C語言動態(tài)生成一些Python代碼之外,并沒有什么用處。我們需要的是C語言的數(shù)據(jù)結(jié)構(gòu)能夠和Python交互。
下面舉個例子,比如說,有一天我們用Python寫了一個功能特別強大的函數(shù):
def great_function(a):
return a + 1
接下來要把它包裝成C語言的函數(shù)。我們期待的C語言的對應(yīng)函數(shù)應(yīng)該是這樣的:
int great_function_from_python(int a) {
int res;
// some magic
return res;
}
首先,復用Python模塊得做‘import’,這里也不例外。所以我們把great_function放到一個module里,比如說,這個module名字叫 great_module.py
接下來就要用C來調(diào)用Python了,完整的代碼如下:
#include Python.h
int great_function_from_python(int a) {
int res;
PyObject *pModule,*pFunc;
PyObject *pArgs, *pValue;
/* import */
pModule = PyImport_Import(PyString_FromString("great_module"));
/* great_module.great_function */
pFunc = PyObject_GetAttrString(pModule, "great_function");
/* build args */
pArgs = PyTuple_New(1);
PyTuple_SetItem(pArgs,0, PyInt_FromLong(a));
/* call */
pValue = PyObject_CallObject(pFunc, pArgs);
res = PyInt_AsLong(pValue);
return res;
}
從上述代碼可以窺見Python內(nèi)部運行的方式:
所有Python元素,module、function、tuple、string等等,實際上都是PyObject。C語言里操縱它們,一律使用PyObject *。
Python的類型與C語言類型可以相互轉(zhuǎn)換。Python類型XXX轉(zhuǎn)換為C語言類型YYY要使用PyXXX_AsYYY函數(shù);C類型YYY轉(zhuǎn)換為Python類型XXX要使用PyXXX_FromYYY函數(shù)。
也可以創(chuàng)建Python類型的變量,使用PyXXX_New可以創(chuàng)建類型為XXX的變量。
若a是Tuple,則a[i] = b對應(yīng)于 PyTuple_SetItem(a,i,b),有理由相信還有一個函數(shù)PyTuple_GetItem完成取得某一項的值。
不僅Python語言很優(yōu)雅,Python的庫函數(shù)API也非常優(yōu)雅。
現(xiàn)在我們得到了一個C語言的函數(shù)了,可以寫一個main測試它
#include Python.h
int great_function_from_python(int a);
int main(int argc, char *argv[]) {
Py_Initialize();
printf("%d",great_function_from_python(2));
Py_Finalize();
}
編譯的方式就用本節(jié)開頭使用的方法。
在Linux/Mac OSX運行此示例之前,可能先需要設(shè)置環(huán)境變量:
bash:
export PYTHONPATH=.:$PYTHONPATH
csh:
setenv PYTHONPATH .:$PYTHONPATH