【问题标题】:Pass C++ object instance to Python function将 C++ 对象实例传递给 Python 函数
【发布时间】:2017-04-24 21:04:14
【问题描述】:

我有一个对象队列,我正在出队以便在返回结果之前获取一个对象并在 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();
};

然后我创建了一个如下所示的 boost 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。 python 文件很简单,我只想将收到的对象打印到控制台上,如下所示:

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

我不确定它是如何与 boost 模块集成的。这样做的正确方法是什么?

【问题讨论】:

    标签: python c++ boost boost-python


    【解决方案1】:

    我已经根据您的 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
    

    希望这是有用的。

    【讨论】:

    • 我似乎找不到 initpydata() 函数。我知道它是自动生成的,因为文档说它会生成 initname() 和 init_module_name()。我可以找到 init_module_pydata()。它们是一样的吗?看起来 init_name 只是将 init_module_name 传递给 c++ 中的 handle_exception()。
    • 在我的示例中的 c++ 代码中,initpydata() 函数是由以 BOOST_PYTHON_MODULE(pydata) { 开头的代码块创建(通过宏)并带入范围的 - 你有这个在你的代码?如果是这样,它应该在那里。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多