使用 boost::python,如何 return 结构向量作为字典列表到 Python?
Using boost::python, how to return vector of structs as list of dicts to Python?
我有以下 C++ 代码:
struct MyType { int x, y; };
struct A {
std::vector<MyType> get_data();
};
我想使用 Boost Python 连接到 Python,以便可以按以下方式使用它:
a = A()
ret = a.get_data();
for r in ret:
print('x=%d; y=%d;' % (r['x'], r['y']))
我现在的想法比较幼稚:
BOOST_PYTHON_MODULE(pyA) {
class_<A>("A").def("get_data", &A::get_data);
}
正如预期的那样,这给了我以下错误
TypeError: No to_python (by-value) converter found for C++ type
当我尝试从 Python 代码调用 get_data()
函数时。
我看到这里的帖子(例如 std::vector to boost::python::list)描述了如何使用 vector_indexing_suite
将某些类型的 std::vector<T>
转换为 list
T
(例如浮点数、字符串),但我不确定如何扩展它来处理我的 struct -> dict 转换。任何帮助将不胜感激。
下文介绍了如何将您的 C++
代码公开给 Python
。 MyType
需要重载 'equal to' 比较运算符,并且 MyType
本身需要暴露给 Python
.
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
using namespace boost::python;
struct MyType {
int x, y;
bool operator==(const MyType& data) const {
return this->x == data.x && this->y == data.y;
}
};
struct A {
std::vector<MyType> get_data() const { return {{1,2},{3,4}};};
};
BOOST_PYTHON_MODULE(pyA) {
class_<MyType>("MyType")
.def_readwrite("x", &MyType::x)
.def_readwrite("y", &MyType::y);
class_<std::vector<MyType>>("MyList")
.def(vector_indexing_suite<std::vector<MyType>>());
class_<A>("A").def("get_data", &A::get_data);
}
下面稍微修改了 Python
脚本。 get_data()
return 类型属于列表,因此需要这样访问。如果你想让它成为一个字典,那么在 Python
.
中将它转换为字典
import pyA
a = pyA.A()
ret = a.get_data();
for r in ret:
print('x=%d; y=%d;' % (r.x, r.y))
最后我采用了如下解决方案,我post在这里,以防将来对其他人有用。这可以通过添加 boost 的 "readonly" 限定符来改进,但我还没有这样做。
#include <boost/python.hpp>
using namespace boost::python;
struct Point {
int x, y;
};
using Points = std::vector<Point>;
struct Converter
{
static PyObject* convert(const Points& v)
{
boost::python::list ret;
for (const auto& c : v) {
boost::python::dict *r = new boost::python::dict();
(*r)["x"] = c.x;
(*r)["y"] = c.y;
ret.append(boost::python::object(*r));
}
return boost::python::incref(ret.ptr());
}
};
BOOST_PYTHON_MODULE(mymodule)
{
boost::python::to_python_converter<Points, Converter>();
class_<MyClass, boost::noncopyable>("MyClass")
.def("get_data", &MyClass::get_data);
}
我有以下 C++ 代码:
struct MyType { int x, y; };
struct A {
std::vector<MyType> get_data();
};
我想使用 Boost Python 连接到 Python,以便可以按以下方式使用它:
a = A()
ret = a.get_data();
for r in ret:
print('x=%d; y=%d;' % (r['x'], r['y']))
我现在的想法比较幼稚:
BOOST_PYTHON_MODULE(pyA) {
class_<A>("A").def("get_data", &A::get_data);
}
正如预期的那样,这给了我以下错误
TypeError: No to_python (by-value) converter found for C++ type
当我尝试从 Python 代码调用 get_data()
函数时。
我看到这里的帖子(例如 std::vector to boost::python::list)描述了如何使用 vector_indexing_suite
将某些类型的 std::vector<T>
转换为 list
T
(例如浮点数、字符串),但我不确定如何扩展它来处理我的 struct -> dict 转换。任何帮助将不胜感激。
下文介绍了如何将您的 C++
代码公开给 Python
。 MyType
需要重载 'equal to' 比较运算符,并且 MyType
本身需要暴露给 Python
.
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
using namespace boost::python;
struct MyType {
int x, y;
bool operator==(const MyType& data) const {
return this->x == data.x && this->y == data.y;
}
};
struct A {
std::vector<MyType> get_data() const { return {{1,2},{3,4}};};
};
BOOST_PYTHON_MODULE(pyA) {
class_<MyType>("MyType")
.def_readwrite("x", &MyType::x)
.def_readwrite("y", &MyType::y);
class_<std::vector<MyType>>("MyList")
.def(vector_indexing_suite<std::vector<MyType>>());
class_<A>("A").def("get_data", &A::get_data);
}
下面稍微修改了 Python
脚本。 get_data()
return 类型属于列表,因此需要这样访问。如果你想让它成为一个字典,那么在 Python
.
import pyA
a = pyA.A()
ret = a.get_data();
for r in ret:
print('x=%d; y=%d;' % (r.x, r.y))
最后我采用了如下解决方案,我post在这里,以防将来对其他人有用。这可以通过添加 boost 的 "readonly" 限定符来改进,但我还没有这样做。
#include <boost/python.hpp>
using namespace boost::python;
struct Point {
int x, y;
};
using Points = std::vector<Point>;
struct Converter
{
static PyObject* convert(const Points& v)
{
boost::python::list ret;
for (const auto& c : v) {
boost::python::dict *r = new boost::python::dict();
(*r)["x"] = c.x;
(*r)["y"] = c.y;
ret.append(boost::python::object(*r));
}
return boost::python::incref(ret.ptr());
}
};
BOOST_PYTHON_MODULE(mymodule)
{
boost::python::to_python_converter<Points, Converter>();
class_<MyClass, boost::noncopyable>("MyClass")
.def("get_data", &MyClass::get_data);
}