【问题标题】:Fails convertion from std::vector<double> to Python list (boost python)从 std::vector<double> 到 Python 列表的转换失败(增强 python)
【发布时间】:2020-01-25 10:41:17
【问题描述】:

我想使用 boost python 创建从 std::vector 到 Python 列表的自定义转换。为此,我遵循to_python_converter 方法。我使用了典型的转换器结构,即

template <class T, bool NoProxy = true>
struct vector_to_list {
  static PyObject* convert(const std::vector<T>& vec) {
    typedef typename std::vector<T>::const_iterator const_iter;
    bp::list* l = new boost::python::list();
    for (const_iter it = vec.begin(); it != vec.end(); ++it) {
      if (NoProxy) {
        l->append(boost::ref(*it));
      } else {
        l->append(*it);
      }
    }
    return l->ptr();
  }
  static PyTypeObject const* get_pytype() { return &PyList_Type; }
};

我可以在很多情况下成功使用它,但它不适用于std::vector&lt;double&gt;。这就是我在我的 boost python 模块中声明这种转换的方式:

BOOST_PYTHON_MODULE(libmymodule_pywrap) {
  .
  .
  .
  bp::to_python_converter<std::vector<double, std::allocator<double> >,
                          vector_to_list<double, false>, true>(); // this doesn't work
  bp::to_python_converter<std::vector<Eigen::VectorXd,
                          std::allocator<Eigen::VectorXd> >,
                          vector_to_list<Eigen::VectorXd, false>, true>(); // this works well
}

我得到以下编译错误:

/usr/include/boost/python/object/make_instance.hpp:27:9: error: no matching function for call to ‘assertion_failed(mpl_::failed************ boost::mpl::or_<boost::is_class<double>, boost::is_union<double>, mpl_::bool_<false>, mpl_::bool_<false>, mpl_::bool_<false> >::************)’
         BOOST_MPL_ASSERT((mpl::or_<is_class<T>, is_union<T> >));
         ^
/usr/include/boost/mpl/assert.hpp:83:5: note: candidate: template<bool C> int mpl_::assertion_failed(typename mpl_::assert<C>::type)
 int assertion_failed( typename assert<C>::type );
     ^
/usr/include/boost/mpl/assert.hpp:83:5: note:   template argument deduction/substitution failed:
/usr/include/boost/python/object/make_instance.hpp:27:9: note:   cannot convert ‘mpl_::assert_arg<boost::mpl::or_<boost::is_class<double>, boost::is_union<double>, mpl_::bool_<false>, mpl_::bool_<false>, mpl_::bool_<false> > >(0u, 1)’ (type ‘mpl_::failed************ boost::mpl::or_<boost::is_class<double>, boost::is_union<double>, mpl_::bool_<false>, mpl_::bool_<false>, mpl_::bool_<false> >::************’) to type ‘mpl_::assert<false>::type {aka mpl_::assert<false>}’
         BOOST_MPL_ASSERT((mpl::or_<is_class<T>, is_union<T> >));

有人明白这是怎么回事吗?

【问题讨论】:

  • 为什么不使用vector_indexing_suite? :class_&lt;std::vector&lt;double&gt;&gt;("vecDouble") .def(vector_indexing_suite&lt;std::vector&lt;double&gt; &gt;());
  • 我知道这种方法,但我决定不遵循它,因为它不是 Pythonic。
  • 同意,它不像 Pythonic 但它带有包装器,似乎需要一些努力才能获得类似的易用性。也许这个(stackoverflow.com/a/15940413/9238288)答案可能会给你一些信息。祝你好运!

标签: python c++ boost converters


【解决方案1】:

我也在学习 Boost::Python,不幸的是不明白如何解决该错误,但这个示例似乎避免了错误消息,您可以根据自己的需要进行修改。

template<typename T>
struct vector_to_list
{
    static PyObject* convert(const std::vector<T>& src)
    {
        boost::python::list result;
        for (int i = 0; i < src.size(); i++)
        {
            result.append(src[i]);
        }

        return boost::python::incref(result.ptr());
    }
};
...
boost::python::to_python_converter<std::vector<double>, vector_to_list<double> >();
...

但是,如果这是为了提供功能,例如:

getData() 在 C++ 中声明:

vector<double> getData() { return m_Data; }

例如,vector&lt;double&gt; m_Data = {1.0, 2.0, 3.0}; 而你想要在 Python 中:

data = example.getData()
print (data)

[1.0, 2.0, 3.0]

您可以通过创建一个通用容器并像这样注册每个容器来实现它(this 回答提供):

/// @brief Type that allows for registration of conversions from
///        python iterable types.
struct iterable_converter
{
  /// @note Registers converter from a python interable type to the
  ///       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 is iterable.
  static void* convertible(PyObject* object)
  {
    return PyObject_GetIter(object) ? object : NULL;
  }

  /// @brief Convert iterable PyObject to C++ container type.
  ///
  /// Container Concept requirements:
  ///
  ///   * Container::value_type is CopyConstructable.
  ///   * Container can be constructed and populated with two 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 is a borrowed reference, so create a handle indicting it is
    // borrowed for proper reference counting.
    python::handle<> handle(python::borrowed(object));

    // Obtain a handle to the memory block that the converter has allocated
    // for the 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 the C++ type into the converter's memory block, and assign
    // its handle to the converter's convertible variable.  The C++
    // container is populated by passing the begin and end iterators of
    // the python object to the container's constructor.
    new (storage) Container(
      iterator(python::object(handle)), // begin
      iterator());                      // end
    data->convertible = storage;
  }
};

BOOST_PYTHON_MODULE(example)
{
    // Register interable conversions.
    iterable_converter()
    .from_python<std::vector<double> > ()
    .from_python<std::vector<Eigen::VectorXd> >()    
    ;
}

这允许链接、嵌套 vectors 和一个比 indexed_vector_suite 更 Pythonic 的 API,例如:

data = example.doubleVector()
data[:] = example.getData()

你可以简单地使用:

data = example.getData()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-19
    • 2020-12-07
    • 1970-01-01
    • 1970-01-01
    • 2021-09-24
    • 2018-09-23
    • 2016-01-24
    • 1970-01-01
    相关资源
    最近更新 更多