2017-04-24 248 views
0

我有一個隊列中的對象,我爲了得到一個對象並在返回結果之前在python中處理它。我有點不確定它是如何融合在一起的,但是從我從各地收集到的,我認爲我非常接近的地方。將C++對象實例傳遞給Python函數

我有一個類,看起來像這樣:

class PyData 
{ 
public: 

    PyData(
     const btVector3 &TORSO_LV, 
     std::vector<std::tuple<float, float, float>> DsOsAVs, 
     std::vector<btVector3> RF_FORCES, 
     std::vector<btVector3> LF_FORCES, 
     float slope, 
     float compliance 
     ); 

    std::tuple<float, float, float> m_TORSO_LV; 
    std::vector<std::tuple<float, float, float>> m_DsOsAVS; 
    std::vector<std::tuple<float, float, float>> m_RF_FORCES; 
    std::vector<std::tuple<float, float, float>> m_LF_FORCES; 

    float m_slope; 
    float m_compliance; 


    ~PyData(); 
}; 

,然後創建一個升壓Python模塊,看起來像這樣:

BOOST_PYTHON_MODULE(pydata) { 
    bp::class_<PyData>("PyData", 
     bp::init< 
      const btVector3, 
      std::vector<std::tuple<float, float, float>>, 
      std::vector<btVector3>, 
      std::vector<btVector3>, 
      float, 
      float 
     >()) 
     .def_readonly("Torso_LV", &PyData::m_TORSO_LV) 
     .def_readonly("DsOsAVs", &PyData::m_DsOsAVS) 
     .def_readonly("RF_FORCES", &PyData::m_RF_FORCES) 
     .def_readonly("LF_FORCES", &PyData::m_LF_FORCES); 
}; 

每33毫秒後,我創建了一個PyData對象,將其放入隊列中。事情是這樣的:

// Check the sample clock for sampling 
    if (m_sampleClock.getTimeMilliseconds() > 33) { 
     if (ContactManager::GetInstance().m_beingUsed) { 
      PyData dat = BuildPyData(); 
      if (dat.m_compliance != 0.0f) { 
       std::unique_lock <std::mutex> l(m_mutex); 
       m_data.push_front(dat); 
       m_NotEmptyCV.notify_one(); 
       l.unlock(); 
      } 
     } 

     m_sampleClock.reset(); 
    } 

然後我有一個單獨的工作線程隊列中取出隊列獲得一個對象,並把它送上一個Python函數看起來像:

void ContactLearningApp::PythonWorkerThread() { 

    printf("Start Python thread. \n"); 

    bp::object f = m_interface.attr("predict_on_data"); 

    while (true) { 
     //printf("Inside while loop and waiting. \n"); 
     std::unique_lock<std::mutex> ul(m_mutex); 
     while (m_data.size() <= 0) { 
      m_NotEmptyCV.wait(ul); 
     } 
     PyData dat = m_data.back(); 
     m_data.pop_back(); 

     f(boost::python::ptr(&dat)); 

     ul.unlock(); 
     //m_ProcessedCV.notify_one(); 
     //bp::exec("print ('Hello from boost')", m_main_namespace); 
    } 

} 

基本上,我想傳遞一個在C++中實例化的對象作爲python參數,但我不知道如何將它拼湊在一起。 python解釋器不需要該對象的副本,所以我使用boost :: python :: ptr。 蟒蛇文件很簡單,我只是想打印出接收在這樣的控制檯對象:

def predict_on_data(data): 
    print("In Predict on Data") 
    print(data) 

我不知道該如何與升壓模塊集成。什麼是正確的方法來做到這一點?

回答

0

我寫了一些基於PyData數據對象的示例代碼;此代碼使用boost :: python數據結構(元組和列表)來交換數據到/從Python交換數據,因爲這是它們的預期用途,但可以通過將數據從std :: tuple和std :: vector如所須。

這適用於Python 2.7和boost 1.53。希望你可以用它來幫助;注意Py_Initialze()後需要調用initpydata()(生成的函數)。

C++代碼:

#include <iostream> 
#include <vector> 
#include <tuple> 
#include <boost/python.hpp> 
#include <boost/python/list.hpp> 

class PyData 
{ 
    public: 

    PyData() {} 

    float m_slope; 
    float m_compliance; 

    boost::python::tuple m_TORSO_LV; 
    boost::python::list  m_DsOsAVS; 
    boost::python::list  m_RF_FORCES; 
    boost::python::list  m_LF_FORCES; 

    void InitData() 
    { 
     // simulate setting up data 
     m_slope = 1.0; 
     m_compliance = 2.0; 

     m_TORSO_LV = boost::python::make_tuple(3.0, 4.0, 5.0); 

     m_DsOsAVS.append(boost::python::make_tuple(10.0, 11.0, 12.0)); 
     m_DsOsAVS.append(boost::python::make_tuple(20.0, 21.0, 22.0)); 

     // etc. 
    } 

    ~PyData() {} 
}; 

BOOST_PYTHON_MODULE(pydata) { 
boost::python::class_<PyData>("PyData") 
    .def_readwrite("Torso_LV", &PyData::m_TORSO_LV) 
    .def_readwrite("DsOsAVs", &PyData::m_DsOsAVS) 
    .def_readwrite("RF_FORCES", &PyData::m_RF_FORCES) 
    .def_readwrite("LF_FORCES", &PyData::m_LF_FORCES) 
    .def_readwrite("slope", &PyData::m_slope) 
    .def_readwrite("compliance", &PyData::m_compliance) 
    ; 
}; 

int main (int argc, char * argv[]) 
{ 
    Py_Initialize(); 

    initpydata(); 

    boost::python::object main=boost::python::import("__main__"); 
    boost::python::object global(main.attr("__dict__")); 
    boost::python::object result = boost::python::exec_file("/home/andy/Python2.py", global, global); 
    boost::python::object predict_on_data = global["predict_on_data"]; 
    if (!predict_on_data.is_none()) 
    { 
     boost::shared_ptr<PyData> o(new PyData); 
     o->InitData(); 
     predict_on_data(boost::python::ptr(o.get())); 
     std::cout << "values in c++ object are now: " << o->m_slope << " and " << o->m_compliance << std::endl; 
    } 

    return 0; 
} 

Python代碼(在本例Python2.py文件):

def predict_on_data(o): 
    print "In Python:" 
    print repr(o) 
    # print the data members in o 
    print "o.slope is " + repr(o.slope) 
    print "o.compliance is " + repr(o.compliance) 
    print "o.Torso_LV is " + repr(o.Torso_LV) 
    print "o.m_DsOsAVs is " + repr(o.DsOsAVs) 
    # modify some data 
    o.slope = -1.0 
    o.compliance = -2.0 

一旦運行這應該給輸出這樣的:

In Python: 
<pydata.PyData object at 0x7f41200956e0> 
o.slope is 1.0 
o.compliance is 2.0 
o.Torso_LV is (3.0, 4.0, 5.0) 
o.m_DsOsAVs is [(10.0, 11.0, 12.0), (20.0, 21.0, 22.0)] 
values in c++ object are now: -1 and -2 

希望這很有用。

+0

我似乎無法找到initpydata()函數。我知道它是自動生成的,因爲文檔說它會生成initname()和init_module_name()。我可以找到init_module_pydata()。它們是一樣的嗎?看起來init_name只是將init_module_name傳遞給C++中的handle_exception()。 – terminix00

+0

在我的例子中的C++代碼中,initpydata()函數被創建(通過宏),並被以BOOST_PYTHON_MODULE(pydata)開頭的代碼塊引入到作用域中(你是否有這樣的代碼?如果是這樣,它應該在那裏。 –