2017-04-24 6 views
0

Ich habe eine Warteschlange von Objekten, die ich aus der Warteschlange nehme, um ein Objekt zu erhalten und es in Python zu verarbeiten, bevor das Ergebnis zurückgegeben wird. Ich bin ein bisschen unsicher, wie das alles zusammenpasst, aber von dem, was ich an verschiedenen Orten gesammelt habe, denke ich, bin ich ziemlich nah dran.C++ - Objektinstanz an Python-Funktion übergeben

Ich habe eine Klasse, die wie folgt aussieht:

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(); 
}; 

und dann erstelle ich einen Schub Python-Modul, das wie folgt aussieht:

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); 
}; 

Nach jeweils 33 ms Ich erstelle ein PyData Objekt und Legen Sie es in die Warteschlange. Etwas wie folgt aus:

// 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(); 
    } 

ich dann einen separaten Arbeitsthread haben, der die Warteschlange aus der Warteschlange entfernt, ein Objekt zu erhalten und senden Sie es an eine Python-Funktion aus, die wie folgt aussieht: Im Grunde genommen

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); 
    } 

} 

, Ich versuche, ein in C++ instanziiertes Objekt als Python-Argument übergeben, aber ich bin mir nicht sicher, wie ich es zusammensetzen soll. Der Python-Interpreter benötigt keine Kopie des Objekts, daher verwende ich boost :: python :: ptr. Die Python-Datei ist einfach und ich möchte nur auszudrucken das Objekt auf die Konsole wie folgt erhalten:

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

Ich bin nicht sicher, wie das mit dem Boost-Modul integriert. Was wäre der richtige Weg, dies zu tun?

Antwort

0

Ich habe einen Beispielcode basierend auf Ihrem PyData-Datenobjekt geschrieben; Dieser Code verwendet die boost :: python-Datenstrukturen (Tupel und Liste) für den Austausch von Daten mit/von Python, da dies ihre beabsichtigte Verwendung ist, aber diese können durch Kopieren von Daten aus std :: tuple und std :: vector in sie gefüllt werden wie benötigt.

Dies funktioniert mit Python 2.7 und Boost 1.53. Hoffentlich können Sie das verwenden, um zu helfen; NB der Aufruf von initpydata() (generierte Funktion) ist nach Py_Initialze() erforderlich.

C++ Code:

#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-Code (Python2.py Datei in diesem Beispiel):

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 

Sobald sie ausgeführt wird diese Ausgabe wie folgt geben sollte:

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 

Hoffnung das ist nützlich.

+0

Ich kann nicht finden, initpydata() -Funktion zu finden. Ich weiß, dass es automatisch generiert wird, da die Dokumentation sagt, dass es initname() und init_module_name() generiert. Ich kann init_module_pydata() finden. Sind sie das Gleiche? Es sieht so aus, als ob init_name nur init_module_name an handle_exception() in C++ übergibt. – terminix00

+0

Im C++ Code in meinem Beispiel wird die initpydata() - Funktion (über Makro) erstellt und durch den Code-Block, der mit BOOST_PYTHON_MODULE (pydata) beginnt, in den Gültigkeitsbereich gebracht - haben Sie das in Ihrem Code? Wenn ja, sollte es da sein. –

Verwandte Themen