4

我正在为现有的 C++ 库编写一个包装器,该库利用列表,其中 T 是自定义结构。有人建议我使用向量而不是列表,但我试图避免修改库。

为了更好地理解这个场景,我制作了一个简单的应用程序,使用一个列表作为代理来注册一个 to-python 转换(它可以是只读的)。

我当前的实现编译得很好,python 导入得很好,可以创建对象,但是当我调用数据成员时,它会出错。

蟒蛇外壳输出:

In [1]: import my_list

In [2]: x = my_list.Bob()

In [3]: x.foos
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-2f015d13a87d> in <module>()
----> 1 x.foos

TypeError: No Python class registered for C++ class std::list<int, std::allocator<int> >

C++ 文件:

#include <list>
#include <boost/python.hpp>

#include <boost/foreach.hpp>
#ifndef FOREACH
    #define FOREACH BOOST_FOREACH
#endif

using namespace std;
using namespace boost::python;

template<typename T>
struct list_to_list
{
    static PyObject* convert(const std::list<T>& src)
    {
        boost::python::list result;
        FOREACH (const T& val, src)
        {
            result.append(val);
        }

        return incref(result.ptr());
    }
};

struct Bob
{
    std::list<int> foos;
};

BOOST_PYTHON_MODULE(my_list)
{
    using namespace boost::python;

    to_python_converter<std::list<int>, list_to_list<int> >();

    class_<Bob>("Bob")
        .def_readonly("foos", &Bob::foos)
    ;
}

我错过了什么吗?

4

1 回答 1

4

常见问题解答中所述,通过def_readonly()def_readwrite()add_property()默认策略公开的属性将不会使用自定义转换器。要解决此问题,请将def_readonly()anddef_readwrite()替换为add_property(),并为 aboost::python::return_value_policy提供boost::python::return_by_value.

在原始代码中,它将是:

BOOST_PYTHON_MODULE(my_list)
{
  using namespace boost::python;

  to_python_converter<std::list<int>, list_to_list<int> >();

  class_<Bob>("Bob")
    .add_property("foos", make_getter(&Bob_foos,
        return_value_policy<return_by_value>())) 
    ;
}

这是一个完整的例子:

#include <list>
#include <boost/assign/list_of.hpp>
#include <boost/foreach.hpp>
#include <boost/python.hpp>

namespace python = boost::python;

/// @brief Type to convert from an iterable to a Python list.
template <typename T>
struct list_to_list
{
  static PyObject* convert(const std::list<T>& container)
  {
    python::list result;
    BOOST_FOREACH(const T& value, container)
      result.append(value);
    return python::incref(result.ptr());
  }
};

/// @brief mockup type.
struct Spam
{
  Spam()
  {
    foos = boost::assign::list_of(1)(2)(3)(5);
  }

  std::list<int> foos;
};

BOOST_PYTHON_MODULE(example)
{
  // Enable std::list<int> to Python list conversion.
  python::to_python_converter<std::list<int>, list_to_list<int> >();

  python::class_<Spam>("Spam")
    .add_property("foo", python::make_getter(&Spam::foos,
          python::return_value_policy<python::return_by_value>()))
    ;
}

以及由此产生的用法:

>>> import example
>>> spam = example.Spam()
>>> spam.foo
[1, 2, 3, 5]
于 2013-10-28T21:29:33.427 回答