2010-11-28 104 views
2

謝謝你的快速回復:) 我想我明白你的建議,但它不完全是我所需要的。說實話,我不知道什麼是正確的技術來做我所需要的。在C++中嵌入Python - 從C++程序運行Python

我有一個程序,它在運行過程中有時需要調用python來執行一些任務。我需要一個函數,調用蟒蛇和捕捉蟒蛇標準輸出

  pythonCallBackFunc(const char* pythonInput) 

此功能是這樣做的功能。

例如:

 pythonCallBackFunc("5**2") needs to print on stdin(or some other file): 
    PythonResult: 25 
    pythonCallBackFunc("print 5**2") needs to print on stdin(or some other file): 
    PythonResult: 25 
    pythonCallBackFunc("'a'+'b'") needs to print on stdin(or some other file): 
    PythonResult: 'ab' 
    pythonCallBackFunc("print 'a'+'b'") needs to print on stdin(or some other file): 
    PythonResult: ab 
    pythonCallBackFunc("execfile('temp.py')") 
    it should print nothing but is needs to run the temp.py script 

    the next 2 calls need to print the value of result, meaning 4. 
    pythonCallBackFunc("result = 4") 
    pythonCallBackFunc("print result") 

我的問題是捕捉所有給定命令(pythonInput)蟒輸出。我試過的第一件事是使用這個腳本python的sdtout和標準錯誤重定向到一個文件:

#stdout.py 
    import sys 
    saveout = sys.stdout          
    fsock = open('out.log', 'w')       
    sys.stdout = fsock          

    #stdout_close.py 
    sys.stdout = saveout          
    fsock.close()   

    #stdout_close.py 
    fsock = open('error.log', 'w')   
    sys.stderr = fsock 

和重定向後,我用的功能Py_run_SimpleString

也沒關係,但是這個功能被忽略這種類型的命令:

Py_run_SimpleString("'a'+'b'") 

輸出是空....

亞歷

+0

我不明白。你評價 - 「5 * 5 + 9」存儲在boostOutputStr中,當然值是34,你做cout <<「Python:」<< boostOutputStr。 – pyfunc 2010-11-28 10:19:48

+0

請注意,如果您有選擇,嵌入Python通常是次優設計。 http://twistedmatrix.com/users/glyph/rant/extendit.html – 2010-11-28 16:59:16

回答

0

首先,請確保您閱讀並理解svenor的答案,如果您嘗試構建比瑣碎的解釋器更復雜的任何東西。然而,在這種特殊情況下,你可以用

std::string boostOutputStr = extract<std::string>(str(result)); 

更換線

int boostOutputStr = extract<int>(result); 

,讓你在找什麼。 str(result)部分將Python表達式求值的任何類型轉換爲其字符串表示形式,如果您只需將其寫入std :: cout就足夠了。

有兩點需要注意,如果你決定去與模板pythonCallBackFunc():

(1)該聲明應該有返回類型「的返回類型」,而不是「無效」

(2),你應該或者調用Py_Initialize()其他地方(如程序/解釋器啓動時)或靜態變量保護它(即 '靜態布爾初始化= FALSE;如果(初始化)!{Py_Initialize();初始化= TRUE;}')

5

您正在使用的示例代碼僅適用於您的Python代碼返回可由C++類型int表示的對象。此行爲是由這行代碼的原因造成的:

int boostOutputStr = extract<int>(result); 

你不得不面對的普遍問題是,C++是一種嚴格的類型語言,而Python是不是。一個python語句(或一個python函數調用)可以返回任何類型的對象,並且對一個函數的一次調用可以返回與下一次調用該函數不同類型的對象。在C++中,函數的返回類型(以及參數的類型)必須定義好。但是,C++爲您希望更靈活的情況提供了模板。通過定義一個模板函數(並且boost :: python的提取函數就是一個很好的例子),您可以將該函數用於不同的類型配置。但是,您的模板函數代碼將由編譯器針對您使用的每種類型進行實例化。即該模板方法僅爲您提供複製和粘貼的繁瑣工作,然後修改您使用它的所有類型的代碼。編譯器爲你所知。但是所有類型在編譯時都必須明確定義。取決於用戶輸入,您有時不能使函數返回int,有時也會返回string。這就是像Python這樣的腳本語言,或者其他高級語言所擅長的。在C++中,必須在編譯代碼時設置所有類型。

那麼你的情況該怎麼辦?

您可以讓pythonCallBackFunc直接返回result,而根本不會將其轉換爲int。所以返回值的類型是object(來自boost :: python),並且代表一個Python對象。你可以用extract<>將它轉換成你以後在代碼中需要的任何類型。 (我假設你確實希望Python表達式的返回值傳回給你的代碼,而不是通過cout一直打印出來。)

或者,你也可以使你的函數pythonCallBackFunc成爲模板函數。

template<class ReturnType> 
    void pythonCallBackFunc(string inputStr){ 
     Py_Initialize(); 
     try 
     { 
     str boostInputStr(inputStr.c_str()); 
     object result = eval(boostInputStr); 

     return extract<ReturnType>(result); 

     //Py_Finalize() #not calling because of the boost.python 
      } 
      catch(error_already_set const &) 
      { 
     //do somthing 
      } 
    } 

...在這種情況下,你必須使用合適的類型來調用它,例如

 pythonCallBackFunc<int>(inputStr); 

希望這是對你的幫助。

+0

感謝您的迴應,這不完全是我所需要的。我試圖制定這個問題威懾... – alexpov 2010-11-29 18:32:16

0

你可以解析字符串並使用PyRun_SimpleString。