我有一个C ++函数,它返回一个结构列表。在结构体内部,有更多的结构列表。
struct CameraInfo {
CamName name;
std::list<CamImageFormat> lImgFormats;
std::list<CamControls> lCamControls;
};
std::list<CameraInfo> getCameraInfo()
{
std::list<CameraInfo> lCamerasInfo;
// fill lCamerasInfo
return lCamerasInfo;
}
然后出口我我正在使用:
class_<CameraNode....> >("CameraNode", no_init)
...
...
.def("listCameraInfo", make_function(&CameraNode::listCameraInfo))
.staticmethod("listCameraInfo")
...
;
这是好的,因为我使用cout在屏幕上打印数据...我现在想要使用返回值和python类属性的内容,这样:
cameras = []
cameras = CameraNode.getCameraInfo()
print cameras[0].name
print cameras[0].lImgFormats[0]
and so on...
这甚至可能吗?我应该使用add_property吗?我不认为我可以为每个结构创建一个类。这个设计在我使用C ++的时候很有意义,但是现在我必须把它包起来,我越来越困惑了。
任何以一般方式使用boost.python包装std :: list的建议都会被广泛接受。
我会在这里添加我发现有用的链接: Iterators StlContainers
答案 0 :(得分:13)
是否必须std::list
?如果您使用std::vector
,则可以使用boost::python::vector_indexing_suite
来包装列表。有关详细信息,请参阅this post。
如果必须使用std::list
,则需要使用python的std::list
方法创建一个包含list
功能的帮助程序类。这可能非常复杂,但可行。
<强> std_item.hpp:强>
#include <list>
#include <algorithm>
#include <boost/python.hpp>
template<class T>
struct listwrap
{
typedef typename T::value_type value_type;
typedef typename T::iterator iter_type;
static void add(T & x, value_type const& v)
{
x.push_back(v);
}
static bool in(T const& x, value_type const& v)
{
return std::find(x.begin(), x.end(), v) != x.end();
}
static int index(T const& x, value_type const& v)
{
int i = 0;
for(T::const_iterator it=x.begin(); it!=x.end(); ++it,++i)
if( *it == v ) return i;
PyErr_SetString(PyExc_ValueError, "Value not in the list");
throw boost::python::error_already_set();
}
static void del(T& x, int i)
{
if( i<0 )
i += x.size();
iter_type it = x.begin();
for (int pos = 0; pos < i; ++pos)
++it;
if( i >= 0 && i < (int)x.size() ) {
x.erase(it);
} else {
PyErr_SetString(PyExc_IndexError, "Index out of range");
boost::python::throw_error_already_set();
}
}
static value_type& get(T& x, int i)
{
if( i < 0 )
i += x.size();
if( i >= 0 && i < (int)x.size() ) {
iter_type it = x.begin();
for(int pos = 0; pos < i; ++pos)
++it;
return *it;
} else {
PyErr_SetString(PyExc_IndexError, "Index out of range");
throw boost::python::error_already_set();
}
}
static void set(T& x, int i, value_type const& v)
{
if( i < 0 )
i += x.size();
if( i >= 0 && i < (int)x.size() ) {
iter_type it = x.begin();
for(int pos = 0; pos < i; ++pos)
++it;
*it = v;
} else {
PyErr_SetString(PyExc_IndexError, "Index out of range");
boost::python::throw_error_already_set();
}
}
};
template<class T>
void export_STLList(const char* typeName)
{
using namespace boost::python;
class_<std::list<T> >(typeName)
.def("__len__", &std::list<T>::size)
.def("clear", &std::list<T>::clear)
.def("append", &listwrap<T>::add,
with_custodian_and_ward<1,2>()) // to let container keep value
.def("__getitem__", &listwrap<T>::get,
return_value_policy<copy_non_const_reference>())
.def("__setitem__", &listwrap<T>::set,
with_custodian_and_ward<1,2>()) // to let container keep value
.def("__delitem__", &listwrap<T>::del)
.def("__contains__", &listwrap<T>::in)
.def("__iter__", iterator<std::list<T> >())
.def("index", &listwrap<T>::index);
}
<强>用法:强>
typedef std::list<int> intlist;
export_STLList<int>("intlist");
答案 1 :(得分:0)
如果单向(从c ++到python)包装就足够了,那么你可以从list<list<YourClass> >
定义直接转换器 - 请参阅我的vector<vector<string> > converter - 只需根据需要更改类型,并且不要别忘了register the converter。
你也可以有一个返回python::list
的方法(它本身包含你的对象的python::list
),这将迭代c ++嵌套列表并从中构建本机python列表,但它会只能在一个案例中工作。
对于双向转换,要么查看我的文件(包含不同类型的双向转换器) - 有利的是你得到原生的python列表,disadvatage就是复制对象。对于大型集合的双向转换,indexing_suite
绝对是可行的方法。
有indexing_suite_v2
,据说情况要好得多,包括对std::list
和std::map
的直接支持,但不幸的是记录得非常严重(上次我看,大约1。5年前)和不是boost::python
的正式部分。