упаковка списка структур с помощью boost.python - PullRequest
5 голосов
/ 21 июля 2011

У меня есть функция 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 ++, но теперь, когда мне нужно было обернуть его, я все больше и больше путаюсь.

Любые советы по упаковке std :: list с boost.python вобщий способ был бы очень хорошо принят.

Редактировать:

Я добавлю сюда ссылки, которые я нашел полезными: Итераторы StlContainers

Ответы [ 2 ]

13 голосов
/ 21 июля 2011

Это должно быть std::list? Если вместо этого вы используете std::vector, вы можете использовать boost::python::vector_indexing_suite для переноса списка. Подробнее см. в этом сообщении .

Если вы должны использовать std::list, вам нужно создать вспомогательный класс, который обернет функциональность std::list методами list python. Это может быть довольно сложным, но выполнимым.

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");
0 голосов
/ 22 июля 2011

Если односторонней (от c ++ до python) упаковки достаточно, вы можете определить прямой преобразователь из list<list<YourClass> > - см. Мой векторконвертер - просто измените типы, как вам нужно, и не забудьте зарегистрируйте конвертер .

У вас также может быть метод, возвращающий python::list (который сам по себе будет содержатьpython::list с вашими объектами), который будет перебирать вложенный список c ++ и создавать из него собственный список Python, но он будет работать только в одном случае, если у вас есть.

Для двусторонних преобразований либопосмотрите на мой файл (который содержит двусторонние конвертеры для разных типов) - преимущество в том, что вы получаете нативные списки Python, disadvatage - это копирование объектов.Для двусторонней конвертации больших коллекций, безусловно, стоит пойти indexing_suite.

Существует indexing_suite_v2, который, как утверждается, намного лучше, включая прямую поддержку std::list и std::map, хотяк сожалению, довольно плохо документировано (последний раз я смотрел около 1,5 лет назад) и не является официальной частью boost::python.

...