【问题标题】:C++ List<T> to Python ListC++ 列表<T> 到 Python 列表
【发布时间】:2013-10-25 18:32:54
【问题描述】:

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

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

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

python shell 输出:

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)
    ;
}

我错过了什么吗?

【问题讨论】:

    标签: c++ python boost type-conversion boost-python


    【解决方案1】:

    FAQ 中所述,通过def_readonly()def_readwrite()add_property() 公开的具有默认策略的属性将不会使用自定义转换器。要解决此问题,请将def_readonly()def_readwrite() 替换为add_property(),提供boost::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]
    

    【讨论】:

    • 它对我有用,但我在另一个项目中没有这个问题:我实现了将 def_readwrite 用于有转换器但没有声明 class_ 的成员。当它在另一种情况下工作时,我找不到它在这里不起作用的地方。这是 boost::python 的最新变化吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    相关资源
    最近更新 更多