2013-05-10 127 views
1

我在使用boost python的C++應用程序中嵌入了python。Boost python,使用命名空間調用函數對象

我想能夠調用一個boost python函數對象,並將全局名稱空間與該函數調用關聯。具體而言,簡化了相關代碼:

bp::object main = bp::import("__main__"); 
bp::object main_namespace = main.attr("__dict__"); 


//Put the function name runPyProg in the main_namespace 

bp::object PyProg = exec(
     "import cStringIO\n" 
     "import sys\n" 
     "sys.stderr = cStringIO.StringIO()\n" 
     "def runPyProg(exp):\n" 
     " print exp\n" 
     " exec(exp)\n" 
     " return\n" 
     "\n",main_namespace); 

//Now call the python function runPyProg with an argument 

bp::object py_fn = main.attr("runPyProg"); 
py_fn(expStr) 

我知道,當我使用升壓蟒蛇exec()函數,我可以在全局命名空間發送,如上圖所示。我的問題是,當我調用py_fn時,如何將main_namespace與python函數關聯?我的最終目標是將runPyProg的局部變量放置在main_namespace中。

謝謝。

回答

3

如果我正確地理解了這個問題,那麼它應該和指定執行exec的上下文一樣簡單。函數或方法可以通過globals()訪問定義它的名稱空間。因此,從runPyProg()內調用globals()將返回等效於Python的main_namespace。此外,exec有兩個可選參數:

  • 第一個參數指定了將用於globals()字典。如果省略第二個參數,那麼它也用於locals()
  • 第二個參數指定將用於locals()的字典。在exec內發生的變化應用於locals()

因此,更改:

exec exp 

exec exp in globals() 

,並應提供所期望的行爲,其中exp可以main_namespace與全局變量交互。


這是一個基本的例子:

#include <boost/python.hpp> 

int main() 
{ 
    Py_Initialize(); 

    namespace python = boost::python; 
    python::object main = python::import("__main__"); 
    python::object main_namespace = main.attr("__dict__"); 

    //Put the function name runPyProg in the main_namespace 
    python::exec(
    "def runPyProg(exp):\n" 
    " print exp\n" 
    " exec exp in globals()\n" 
    " return\n" 
    "\n", main_namespace); 

    // Now call the python function runPyProg with an argument 
    python::object runPyProg = main.attr("runPyProg"); 

    // Set x in python and access from C++. 
    runPyProg("x = 42"); 
    std::cout << python::extract<int>(main.attr("x")) << std::endl; 

    // Set y from C++ and access within python. 
    main.attr("y") = 100; 
    runPyProg("print y"); 

    // Access and modify x in python, then access from C++. 
    runPyProg("x += y"); 
    std::cout << python::extract<int>(main.attr("x")) << std::endl; 
} 

評論輸出:

x = 42   // set from python 
42    // print from C++ 
       // y set to 100 from C++ 
print y   // print y from python 
100    // 
x += y   // access and modify from python 
142    // print x from C++ 
+0

謝謝坦納,該解決方案運行良好! – user773494 2013-05-13 21:39:39

+0

所以我意識到如果我有一個C++類PyExpression,並且類的每個實例都調用boost python exec()來執行它自己的表達式,那麼所有實例實際上都使用相同的全局名稱空間。有沒有辦法將名稱空間的範圍保留到PyExpression的每個C++實例?當我嘗試傳遞未初始化爲main.attr(「__ dict__」)的boost :: python ::對象時,exec()會引發錯誤。 – user773494 2013-05-14 14:45:40

+0

@ user773494:命名空間只是Python中的字典。或者更新'runPyProg'來接受它將執行表達式的命名空間(可能是'PyExpression'實例上的'__dict__'對象),或者使用['inspect'](http://docs.python.org/ 2/library/inspect.html)模塊從堆棧中提取所需的名稱空間。 – 2013-05-14 15:05:43

相關問題