【问题标题】:std::vector to boost::python::liststd::vector 到 boost::python::list
【发布时间】:2011-05-27 20:32:51
【问题描述】:

我有一个从 python 调用的 c++ 方法,需要返回一个 python 列表对象。

我已经创建了该方法,并将其附加到一个公开的类并且现在可以从 python 调用...(它返回 void)。

所以问题是,我如何从中创建一个 python 列表:

std::vector<std::string> results;

我不是很了解这个文档中的构造函数是如何工作的:

http://www.boost.org/doc/libs/1_37_0/libs/python/doc/v2/list.html

另外...我真的不想返回某种包装的向量...我只想使用来自向量的字符串值创建一个新的 Python 列表。

如果这是重复的,我深表歉意...我找到了很多向量问题列表,但我找不到任何关于创建新 python 列表的信息。

我可以扩展这个问题以包括其他一些问题,例如:

从 a:std::map<std::string, std::string> 等创建一个新的 Python 字典。

【问题讨论】:

标签: c++ boost-python


【解决方案1】:

boost::python 已经包含包装矢量和地图的功能。这是向量的示例代码,您可以看到传递和返回列表都非常简单:

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

地图与向量非常相似,在这篇文章中有描述: Boost::Python- possible to automatically convert from dict --> std::map?

很遗憾,boost::python 目前不包括用于包装列表的工具。您可以手动创建包装器,但我没有时间回答这个问题。我可以在今天或明天发布。我很感激关于这个特定问题的新问题,因为答案将非常广泛,并且可能超出了本文的范围。我只是避免使用列表并使用向量。

【讨论】:

  • 你好@Aleksey,我想我有一个相关的问题要问你link
  • 谢谢,顺便问一下,这种方法开销大吗?抱歉,我是 C++ 和 boost.python 的新手。
  • 可以分享vector_indexing_suite对应文档的链接吗。
  • 所有vector_indexing_suite 所做的只是为std::vector 创建一个python 包装器。这意味着直接访问std::vector。这基本上是您希望的最低开销。这是链接:boost.org/doc/libs/1_68_0/libs/python/doc/html/reference/topics/…
【解决方案2】:

我有这个函数使用迭代器将std::vector 转换为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;
}

【讨论】:

  • 没有这么大的开销吗?这真是一个问题
  • 我试过了,我在 py::object iter = get_iter(v) 上遇到了一个异常:No to_python (by-value) converter found for C++ type: class std::vector&lt;int,class std::allocator&lt;int&gt; &gt; 从 Boost 1.51 开始
  • 同样 '未找到 C++ 类型的 to_python(按值)转换器:std::vector<:string std::allocator>>', boost 1.48跨度>
  • 同样的错误,: No to_python (by-value) converter found for C++ type: std::vector >
  • 这里同样的错误:No to_python (by-value) converter found for C++ type: std::vector&lt;int, std::allocator&lt;int&gt; &gt;
【解决方案3】:

如果您只想手动创建 python 列表(并让函数返回 py::list 而不是向量),请这样做:

/* 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;

对于自动转换,定义向量从 python 列表到 c++ 以及从 c++ 到 python 列表的转换器—​​—我刚刚在Instantiating shared_ptr's in boost::python(回复的第二部分)写过这个;这样,你就得到了真正的 python 列表。

自动转换的另一种可能性(我没有经验)是使用 indexing_suite,它会将vector&lt;string&gt; 包装为 python 中的一个特殊类,正如这里已经提到的一位同事。

【讨论】:

    【解决方案4】:

    来自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;
    }
    

    【讨论】:

    • 是的,它可以工作,但我不确定是否必须迭代向量并附加每个元素是否有太多开销。也许使用 numpy 数组更有效?
    【解决方案5】:

    FWIW,这是一个与 eudoxos 解决方案相同的模板函数:

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

    【讨论】:

    • 这会复制附加到列表中的值,对吗?有什么方法可以避免这种情况(假设值是某种类类型),所以在 python 中 get_list(0) == get_list(0) 返回 true?类似于bp::reference_existing_object 但在函数内?
    【解决方案6】:

    我使用以下实用程序函数来转换/转换为 stl 容器。简单的 sum 函数说明了它们是如何使用的。我还发现了以下具有很多转换实用程序的开源包: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);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-07-24
      • 2014-01-11
      • 2021-12-16
      • 2011-09-17
      • 2012-05-07
      • 1970-01-01
      • 2017-02-01
      相关资源
      最近更新 更多