2012-12-05 128 views
5

因此,我正在開發一個小型項目,在該項目中,我將Python用作嵌入式腳本引擎。到目前爲止,使用boost.python我沒有遇到太多麻煩,但是如果可能的話,我想用它做些什麼。Boost.Python - 將boost :: python :: object作爲參數傳遞給python函數?

基本上,Python可以通過向類中添加函數甚至數據值來擴展我的C++類。我希望能夠將這些持久化在C++端,所以一個python函數可以將數據成員添加到類中,然後傳遞給不同函數的同一個實例仍然會擁有它們。這裏的目標是用C++編寫一個通用的核心引擎,並讓用戶以任何他們需要的方式將其擴展到Python,而無需觸及C++。

所以,我認爲會的工作是,我會在C++類boost::python::object存儲爲值self,並調用從C++蟒蛇的時候,我會通過boost::python::ptr()發送Python對象,以便在修改python方面會堅持回到C++類。不幸的是,當我嘗試,我得到了以下錯誤:

TypeError: No to_python (by-value) converter found for C++ type: boost::python::api::object

是否有直接傳遞對象到Python函數一樣,任何方式或任何其他方式,我可以去這個實現我想要的結果?

在此先感謝您的幫助。 :)

+0

找到了一個解決方案。在python中,我添加了一個函數: def ProcessEvent(event,obj): return globals()[event](obj.PyObj) 在C++中,我添加了一個'boost :: python :: object'給我的C++類命名'PyObj',該類初始化爲'boost :: python :: ptr(this)',並用它來調用我的事件,傳遞我想調用的事件的名稱作爲第一個參數, boost :: python :: ptr'作爲第二個我想傳遞給它的對象。這符合我的希望 - 當我在一個事件中添加屬性時,它在我傳遞給另一個事件時仍然存在。也許不是最好的解決方案...但是,它的工作原理。 –

回答

5

從C++的郵件列表中得到了這個奇妙的解決方案。

在C++類中實現std::map<std::string, boost::python::object>,然後重載__getattr__()__setattr__()來讀取和寫入std :: map。然後像往常一樣將它發送到Python的boost::python::ptr(),不需要在C++端保留一個對象或發送一個到python。它完美的作品。

編輯:我也發現我不得不以一種特殊的方式覆蓋__setattr__()函數,因爲它破壞了我添加的add_property()。這些東西在得到它們的時候工作得很好,因爲python在調用__getattr__()之前檢查了一個類的屬性,但是__setattr__()沒有這樣的檢查。它只是直接調用它。所以我必須做出一些改變才能把它變成一個完整的解決方案。下面是完整的實施解決方案:

首先創建一個全局變量:

boost::python::object PyMyModule_global; 

創建一個類,如下所示(以要添加到它的任何其他信息):

class MyClass 
{ 
public: 
    //Python checks the class attributes before it calls __getattr__ so we don't have to do anything special here. 
    boost::python::object Py_GetAttr(std::string str) 
    { 
     if(dict.find(str) == dict.end()) 
     { 
     PyErr_SetString(PyExc_AttributeError, JFormat::format("MyClass instance has no attribute '{0}'", str).c_str()); 
     throw boost::python::error_already_set(); 
     } 
     return dict[str]; 
    } 

    //However, with __setattr__, python doesn't do anything with the class attributes first, it just calls __setattr__. 
    //Which means anything that's been defined as a class attribute won't be modified here - including things set with 
    //add_property(), def_readwrite(), etc. 
    void Py_SetAttr(std::string str, boost::python::object val) 
    { 
     try 
     { 
     //First we check to see if the class has an attribute by this name. 
     boost::python::object obj = PyMyModule_global["MyClass"].attr(str.c_str()); 
     //If so, we call the old cached __setattr__ function. 
     PyMyModule_global["MyClass"].attr("__setattr_old__")(ptr(this), str, val); 
     } 
     catch(boost::python::error_already_set &e) 
     { 
     //If it threw an exception, that means that there is no such attribute. 
     //Put it on the persistent dict. 
     PyErr_Clear(); 
     dict[str] = val; 
     } 
    } 
private: 
    std::map<std::string, boost::python::object> dict; 
}; 

然後定義python模塊,如下所示,添加任何其他的defs和你想要的屬性:

BOOST_PYTHON_MODULE(MyModule) 
{ 
    boost::python::class_<MyClass>("MyClass", boost::python::no_init) 
     .def("__getattr__", &MyClass::Py_GetAttr) 
     .def("__setattr_new__", &MyClass::Py_SetAttr); 
} 

然後初始化蟒蛇:

void PyInit() 
{ 
    //Initialize module 
    PyImport_AppendInittab("MyModule", &initMyModule); 
    //Initialize Python 
    Py_Initialize(); 

    //Grab __main__ and its globals 
    boost::python::object main = boost::python::import("__main__"); 
    boost::python::object global = main.attr("__dict__"); 

    //Import the module and grab its globals 
    boost::python::object PyMyModule = boost::python::import("MyModule"); 
    global["MyModule"] = PyMyModule; 
    PyMyModule_global = PyMyModule.attr("__dict__"); 

    //Overload MyClass's setattr, so that it will work with already defined attributes while persisting new ones 
    PyMyModule_global["MyClass"].attr("__setattr_old__") = PyMyModule_global["MyClass"].attr("__setattr__"); 
    PyMyModule_global["MyClass"].attr("__setattr__") = PyMyModule_global["MyClass"].attr("__setattr_new__"); 
} 

一旦你完成了這一切,你就可以堅持的變化在Python轉移到C++進行的實例。任何在C++中定義爲屬性的東西都會被正確處理,任何不會被附加到dict而不是類__dict__

+0

太棒了!感謝分享! – mrmclovin

相關問題