std::vector to boost::python::list

后端 未结 6 637
星月不相逢
星月不相逢 2020-11-27 02:28

I have a method in c++ that gets called from python and needs to return a python list object.

I have already created the method, and its attached to an exposed class

相关标签:
6条回答
  • 2020-11-27 03:08

    If you only want to create python list manually (and have the function return py::list rather than vector), do it like this:

    /* using namespace std; namespace py=boost::python;
       #define FOREACH BOOST_FOREACH
    */
    vector<string> ss;
    py::list ret;
    FOREACH(const string& s, ss) ret.append(s);
    return s;
    

    For automatic conversions, define the converter for vector from python list to c++ and from c++ to python list -- I just wrote about that at Instantiating shared_ptr's in boost::python (the second part of the reply); that way, you get realy python lists.

    Another possibility for automatic conversion (which I have no experience with) is to use indexing_suite, which will wrap vector<string> as a special class in python, as a colleague mentioned here already.

    0 讨论(0)
  • 2020-11-27 03:11

    I use following utility functions to convert from/to stl containers. The trivial sum function illustrates how they are used. Also I found following opensource package which has quite a few conversion utilities: https://github.com/cctbx/cctbx_project/tree/master/scitbx/boost_python

    #include <vector>
    #include <boost/python.hpp>
    #include <boost/python/object.hpp>
    #include <boost/python/stl_iterator.hpp>
    
    namespace bpy = boost::python;
    
    namespace fm {
    
    template <typename Container>
    bpy::list stl2py(const Container& vec) {
      typedef typename Container::value_type T;
      bpy::list lst;
      std::for_each(vec.begin(), vec.end(), [&](const T& t) { lst.append(t); });
      return lst;
    }
    
    template <typename Container>
    void py2stl(const bpy::list& lst, Container& vec) {
      typedef typename Container::value_type T;
      bpy::stl_input_iterator<T> beg(lst), end;
      std::for_each(beg, end, [&](const T& t) { vec.push_back(t); });
    }
    
    bpy::list sum(const bpy::list& lhs, const bpy::list& rhs) {
      std::vector<double> lhsv;
      py2stl(lhs, lhsv);
    
      std::vector<double> rhsv;
      py2stl(rhs, rhsv);
    
      std::vector<double> result(lhsv.size(), 0.0);
      for (int i = 0; i < lhsv.size(); ++i) {
        result[i] = lhsv[i] + rhsv[i];
      }
      return stl2py(result);
    }
    
    } // namespace fm
    
    BOOST_PYTHON_MODULE(fm)
    {
      bpy::def("sum", &fm::sum);
    }
    
    0 讨论(0)
  • 2020-11-27 03:12

    From http://gist.github.com/octavifs/5362272:

    // Converts a C++ vector to a python list
    template <class T>
    boost::python::list toPythonList(std::vector<T> vector) {
        typename std::vector<T>::iterator iter;
        boost::python::list list;
        for (iter = vector.begin(); iter != vector.end(); ++iter) {
            list.append(*iter);
        }
        return list;
    }
    
    0 讨论(0)
  • 2020-11-27 03:13

    FWIW, here's a templated function in the same vein as eudoxos' solution:

    namespace py = boost::python;
    
    template<class T>
    py::list std_vector_to_py_list(const std::vector<T>& v)
    {
      py::list l;
      typename std::vector<T>::const_iterator it;
      for (it = v.begin(); it != v.end(); ++it)
        l.append(*it);   
      return l;  
    }
    
    0 讨论(0)
  • 2020-11-27 03:14

    I have this function using iterators to convert std::vector to py::list:

    namespace py = boost::python;
    
    template<class T>
    py::list std_vector_to_py_list(const std::vector<T>& v)
    {
        py::object get_iter = py::iterator<std::vector<T> >();
        py::object iter = get_iter(v);
        py::list l(iter);
        return l;
    }
    
    0 讨论(0)
  • 2020-11-27 03:19

    boost::python already includes functionality for wrapping vectors and maps. Here's sample code for vectors, as you can see both passing and returning lists is quite simple:

    // C++ code
    typedef std::vector<std::string> MyList;
    class MyClass {
      MyList myFuncGet();
      void myFuncSet(const Mylist& list);
      //       stuff
    };
    
    // Wrapper code
    
    #include <boost/python/suite/indexing/vector_indexing_suite.hpp>
    
    using namespace boost::python;
    
    
    BOOST_PYTHON_MODULE(mymodule)
    {
        class_<MyList>("MyList")
            .def(vector_indexing_suite<MyList>() );
    
        class_<MyClass>("MyClass")
            .def("myFuncGet", &MyClass::myFuncGet)
            .def("myFuncSet", &MyClass::myFuncSet)
            ;
    }
    

    Maps are very similar to vectors and are described in this post: Boost::Python- possible to automatically convert from dict --> std::map?

    Unfortunately boost::python does not currently include facilities for wrapping lists. You can create the wrapper manually, but I'm out of time for this answer. I can post it today or tomorrow. I'd appreciate a new question about this particular problem, because the answer will be quite extensive and is probably outside of the scope of this post. I'd just avoid lists and use vectors instead.

    0 讨论(0)
提交回复
热议问题