将 C++ 对象实例传递给 Python 函数
Pass C++ object instance to Python function
我有一个对象队列,我正在将其出队,以便在返回结果之前获取一个对象并在 python 中对其进行处理。我有点不确定它们是如何组合在一起的,但从我从不同地方收集到的信息来看,我认为我非常接近。
我有一个 class 看起来像这样:
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 模块集成的。执行此操作的正确方法是什么?
我已经根据您的 PyData 数据对象编写了一些示例代码;此代码使用 boost::python 数据结构(元组和列表)交换数据 to/from 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
希望这有用。
我有一个对象队列,我正在将其出队,以便在返回结果之前获取一个对象并在 python 中对其进行处理。我有点不确定它们是如何组合在一起的,但从我从不同地方收集到的信息来看,我认为我非常接近。
我有一个 class 看起来像这样:
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 模块集成的。执行此操作的正确方法是什么?
我已经根据您的 PyData 数据对象编写了一些示例代码;此代码使用 boost::python 数据结构(元组和列表)交换数据 to/from 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
希望这有用。