python是一門很優秀的腳本語言,語法簡潔而清晰,具有豐富和強大的類庫。它常被昵稱為膠水語言,它能夠很輕松的把用其他語言制作的各種模塊。 但是python的界面設計我們並不是很熟悉(雖然他也有很多很好的且功能強大的類庫,例如wxpython等,但是相比其他的GUI設計,我們可能更加 熟悉QT或者MFC,因此不太會選用python作為界面設計的工具),所以我們在很多情況下,很難在有界面需求的項目中使用python的GUI去設 計。但是這樣並不意味着我們不能依靠python的高效,簡潔去做一些東西,我們可以用python做一些模塊,然后再其他的編程語言中去調用她,下面就 舉例一些相關的函數。
如果你在C代碼中去調用python,那么你首先要做到就是初始化python環境。具體使用的函數如下為Py_Initialize()。當你 正確的將python環境初始化之后,就可以用最簡單的一個CPython接口去跑一些腳本,該函數為PyRun_SimpleString(s),這個 函數大家一看就知道是用來干啥的了吧。使用該函數能夠讓你直接在參數里面寫一些python,然后python環境就會調用這個函數,完成你所寫的 python語句。例如PyRun_SimpleString("import tree"),使用這個語句,就能在C環境中使用python加載了 tree.py這個模塊。
接下來,我們就要獲得模塊中定義的一些函數,大家知道,python里面的模塊里面會定義很多的函數,類。當我們在python中對相關模塊進行 import之后就能夠直接調用了,那么我們在C中要如何獲得這些函數、類呢?這些函數,類又是些什么東西呢。這就涉及到python的一些基本機制了, 其實在python里面,一切的東西都是對象,他們有共同的基類PyObject,至於這個PyObject具體是什么,這里就不展開了。因此我們可以得 出一些思路,那既然一切都是PyObject,那么我們在C里面使用PyObject將函數與類接進來不就好了。
現在讓我們回到我們運行了PyRun_SimpleString("import tree"),此時我們已經在運行環境中加載了tree.py這個模塊 了,那這個模塊又是什么呢。根據上文,大家應該能猜到,沒錯,這個模塊也是個以PyObject為基類的對象。此時對應的函數為 (PyObject *) PyImport_ImportModule(const char *name)或者 (PyObject *) PyImport_Import(PyObject *name)(兩者的區別為,如果使用后者,你需要將模塊的名稱(通常是 char*)轉換成PyObject對象),此時你就會得到一個類型為PyObject的moudle對象。
對於這個moudle對象,這里就不賣關子了,它實際上是一個python中的特殊的dict對象,里面有各種包含了這個moudle中的所有的類函數等 信息。因此,從這個moudle中獲得相關的類和函數就是手到擒來的事情了。首先我們將這個moudle返回成一個dict對象,使用的函數為 (PyObject *) PyModule_GetDict(PyObject *)然后就使用 (PyObject *) PyDict_GetItemString(PyObject *dp, const char *key)來獲得相關的函數 與類。如果是類的話,那獲得的只是一個類定義,我們還需要將其構造成對象,使用的接口為 (PyObject *) PyInstance_New(PyObject *, PyObject *,PyObject *)具體的函數這里就不展 開了,大家網上找找吧。
下面是網上的一個代碼,比較詳細的說了這一系列過程,大家可以試一試,源網址找不到了,悲劇,就直接貼代碼了:
def hello(s):
print "hello world"
print s
def arg(a, b):
print 'a=', a
print 'b=', b
return a + b
class Test:
def __init__(self):
print "init"
def say_hello(self, name):
print "hello,", name
return name
// pytest.cpp : 定義控制台應用程序的入口點。
//
#include "stdafx.h"
#include <Python.h>
int main(int argc, char* argv[])
{
//初始化python
Py_Initialize();
//定義python類型的變量
PyObject *pModule = NULL;
PyObject *pFunc = NULL;
PyObject *pArg = NULL;
PyObject *result = NULL;
PyObject *pClass = NULL;
PyObject *pInstance = NULL;
PyObject *pDict = NULL;
//直接運行python代碼
PyRun_SimpleString("print 'python start'");
//引入模塊
pModule = PyImport_ImportModule("test_code");
//獲取模塊字典屬性
pDict = PyModule_GetDict(pModule);
//直接獲取模塊中的函數
pFunc = PyObject_GetAttrString(pModule, "hello");
//參數類型轉換,傳遞一個字符串。將c/c++類型的字符串轉換為python類型,元組中的python類型查看python文檔
pArg = Py_BuildValue("(s)", "hello charity");
//調用直接獲得的函數,並傳遞參數
PyEval_CallObject(pFunc, pArg);
//從字典屬性中獲取函數
pFunc = PyDict_GetItemString(pDict, "arg");
//參數類型轉換,傳遞兩個整型參數
pArg = Py_BuildValue("(i, i)", 1, 2);
//調用函數,並得到python類型的返回值
result = PyEval_CallObject(pFunc, pArg);
//c用來保存c/c++類型的返回值
int c;
//將python類型的返回值轉換為c/c++類型
PyArg_Parse(result, "i", &c);
//輸出返回值
printf("a+b=%d\n", c);
//通過字典屬性獲取模塊中的類
pClass = PyDict_GetItemString(pDict, "Test");
//實例化獲取的類
pInstance = PyInstance_New(pClass, NULL, NULL);
//調用類的方法
result = PyObject_CallMethod(pInstance, "say_hello", "(s)", "charity");
//輸出返回值
char* name=NULL;
PyArg_Parse(result, "s", &name); //這個函數的第二個參數相當扯淡,具體看下文的英文,類型使用字符來表示的,例如“s”代表
//str "i" 代表int,個人感覺相當扯淡
printf("%s\n", name);
PyRun_SimpleString("print 'python end'");
//釋放python
Py_Finalize();
getchar();
return 0;
}
運行結果:
python start
hello world
hello charity
a= 1
b= 2
a+b=3
init
hello, charity
charity
python end