C與python的調用一(導入python模塊與,獲得函數與類)


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM