用boost.python包装结构列表 [英] wrapping a list of structs with boost.python
问题描述
我有一个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)
...
;
这是OK,因为我使用cout在屏幕上打印数据...我想现在使用返回值和它的内容从python像属性,这样:
cameras = []
= CameraNode.getCameraInfo()
print cameras [0] .name
print cameras [0] .lImgFormats [0]
等等...
这是可能吗?我应该使用add_property?我不认为我可以为每个结构创建一个类。这个设计是有意义的,而我在使用C ++,但现在,我必须包装它,我越来越困惑。
任何建议, :: list with boost.python in a general way will be very well accepted。
编辑:
将添加我发现有用的链接:
迭代器
StlContainers $ d
是否必须 std :: list
?如果你使用 std :: vector
,你可以使用 boost :: python :: vector_indexing_suite
包装列表。有关详情,请参见此帖。
如果你必须使用 std :: list
,你需要创建一个包装 std: :list
功能与python的列表
方法。
std_item.hpp:
$ p> #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
}
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 <
i + = x.size();
if(i> = 0&& i<(int)x.size()){
iter_type it = x.begin();
for(int pos = 0; 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>())//让容器保持值
.def (__getitem__,& listwrap< T> :: get,
return_value_policy< copy_non_const_reference>())
.def(__ setitem__,& listwrap& b with_custodian_and_ward< 1,2>())//以使容器保持值
.def(__ delitem__,& listwrap< T> :: del)
.def(__ contains__ ; listwrap< T> :: in)
.def(__ iter__,iterator< std :: list>>())
.def(index,& listwrap< T> ;::指数);
}
用法: b
typedef std :: list< int> intlist;
export_STLList< int>(intlist);
I have a C++ function that returns a list of structs. Inside the struct, there are more lists of structs.
struct CameraInfo {
CamName name;
std::list<CamImageFormat> lImgFormats;
std::list<CamControls> lCamControls;
};
std::list<CameraInfo> getCameraInfo()
{
std::list<CameraInfo> lCamerasInfo;
// fill lCamerasInfo
return lCamerasInfo;
}
then for exporting it I was using:
class_<CameraNode....> >("CameraNode", no_init)
...
...
.def("listCameraInfo", make_function(&CameraNode::listCameraInfo))
.staticmethod("listCameraInfo")
...
;
And it was OK since I was using cout to print the data on screen... I would like now to use the return value and it's content from python like properties, this way:
cameras = []
cameras = CameraNode.getCameraInfo()
print cameras[0].name
print cameras[0].lImgFormats[0]
and so on...
Is this even possible?? Should I be using add_property instead? I don't think I can create a class for every struct. This design made sense while I was working on C++ only but now that I would have to wrap it, I'm getting more and more confused.
Any advice on wrapping std::list with boost.python in a general way would be very well accepted.
Edit:
I will add here links that I've found useful: Iterators StlContainers
Does it have to be std::list
? If you use std::vector
instead you can use boost::python::vector_indexing_suite
to wrap the list. See this post for details.
If you must use std::list
you'll need to create a helper class that wraps the std::list
functionality with python's list
methods. That can be quite involved, but doable.
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);
}
usage:
typedef std::list<int> intlist;
export_STLList<int>("intlist");
这篇关于用boost.python包装结构列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!