Feeding a Python list into a function taking in a vector with Boost Python -


i've got function signature:

function(std::vector<double> vector); 

and i've exposed it, doesn't take in python lists. i've looked through other answers, , involve changing function take in boost::python::lists, don't want change function. imagine can use vector_indexing_suite write simple wrapper around function, have many functions of form , rather not write wrapper every single one. there way automatically make python list->std::vector mapping occur?

there few solutions accomplish without having modify original functions.

to accomplish small amount of boilerplate code , transparency python, consider registering custom converter. boost.python uses registered converters when going between c++ , python types. converters implicitly created when creating bindings, such when class_ exports type.

the following complete example uses iterable_converter type allows registration of conversion functions python type supporting python iterable protocol. example enable conversions for:

  • collection of built-in type: std::vector<double>
  • 2-dimensional collection of strings: std::vector<std::vector<std::string> >
  • collection of user type: std::list<foo>
#include <iostream> #include <list> #include <vector> #include <boost/python.hpp> #include <boost/python/stl_iterator.hpp>  /// @brief mockup model. class foo {};  // test functions demonstrating capabilities.  void test1(std::vector<double> values) {   (auto&& value: values)     std::cout << value << std::endl; }  void test2(std::vector<std::vector<std::string> > values) {   (auto&& inner: values)     (auto&& value: inner)       std::cout << value << std::endl; }   void test3(std::list<foo> values) {   std::cout << values.size() << std::endl; }  /// @brief type allows registration of conversions ///        python iterable types. struct iterable_converter {   /// @note registers converter python interable type   ///       provided type.   template <typename container>   iterable_converter&   from_python()   {     boost::python::converter::registry::push_back(       &iterable_converter::convertible,       &iterable_converter::construct<container>,       boost::python::type_id<container>());      // support chaining.     return *this;   }    /// @brief check if pyobject iterable.   static void* convertible(pyobject* object)   {     return pyobject_getiter(object) ? object : null;   }    /// @brief convert iterable pyobject c++ container type.   ///   /// container concept requirements:   ///   ///   * container::value_type copyconstructable.   ///   * container can constructed , populated 2 iterators.   ///     i.e. container(begin, end)   template <typename container>   static void construct(     pyobject* object,     boost::python::converter::rvalue_from_python_stage1_data* data)   {     namespace python = boost::python;     // object borrowed reference, create handle indicting     // borrowed proper reference counting.     python::handle<> handle(python::borrowed(object));      // obtain handle memory block converter has allocated     // c++ type.     typedef python::converter::rvalue_from_python_storage<container>                                                                 storage_type;     void* storage = reinterpret_cast<storage_type*>(data)->storage.bytes;      typedef python::stl_input_iterator<typename container::value_type>                                                                     iterator;      // allocate c++ type converter's memory block, , assign     // handle converter's convertible variable.  c++     // container populated passing begin , end iterators of     // python object container's constructor.     new (storage) container(       iterator(python::object(handle)), // begin       iterator());                      // end     data->convertible = storage;   } };  boost_python_module(example) {   namespace python = boost::python;    // register interable conversions.   iterable_converter()     // build-in type.     .from_python<std::vector<double> >()     // each dimension needs convertable.     .from_python<std::vector<std::string> >()     .from_python<std::vector<std::vector<std::string> > >()     // user type.     .from_python<std::list<foo> >()     ;    python::class_<foo>("foo");    python::def("test1", &test1);   python::def("test2", &test2);   python::def("test3", &test3); } 

interactive usage:

>>> import example >>> example.test1([1, 2, 3]) 1 2 3 >>> example.test1((4, 5, 6)) 4 5 6 >>> example.test2([ ...   ['a', 'b', 'c'], ...   ['d', 'e', 'f'] ... ]) b c d e f >>> example.test3([example.foo(), example.foo()]) 2 

a few comments on approach:

  • the iterable_converter::convertible function changed allowing python list, rather allowing type supports iterable protocol. however, extension may become unpythonic result.
  • the conversions registered based on c++ types. thus, registration needs done once, same registered conversion selected on number of exported functions accept c++ type argument.
  • it not introduce unnecessary types example extension namespace.
  • meta-programming allow multi-dimensional types recursively register each dimension type. however, example code complex enough, did not want add additional level of complexity.

alternative approaches include:

  • create custom function or template function accepts boost::python::list each function accepting std::vector. approach causes bindings scale based on amount of functions being exported, rather amount of types needing converted.
  • using boost.python vector_indexing_suite. *_indexing_suite classes export type adapted match semantics of python list or dictionaries. thus, python code has know exact container type provide, resulting in less-pythonic extension. example, if std::vector<double> exported vecdouble, resulting python usage be:

    v = example.vecdouble() v[:] = [1, 2, 3] example.test1(v) 

    however, following not work because exact types must match, exporting class registers conversion between vecdouble , std::vector<double>:

    example.test1([4, 5, 6]) 

    while approach scales types rather functions, results in less pythonic extension , bloats example namespace unnecessary types.


Comments

Popular posts from this blog

ios - iPhone/iPad different view orientations in different views , and apple approval process -

java Extracting Zip file -

C# WinForm - loading screen -