如何使用boost :: python通过引用传递非const std :: vector <double>?

时间:2015-11-18 14:47:55

标签: python c++ boost-python

我希望能够提供一个空的std::vector<double>&作为Python函数的参数来填充它。这样的事情:

Python文件Foo.py:

class Foo :
  def bar(self, x) :
    x.push_back(3.14)
foo = Foo()

C ++代码:

Py_Initialize();
boost::python::object pyobj_main = boost::python::import("__main__");
boost::python::object glob = pyobj_main.attr("__dict__");
glob["std_vector_double"] = boost::python::class_< std::vector<double> >("std_vector_double").def(boost::python::vector_indexing_suite< std::vector<double> >());

boost::python::exec_file("Foo.py", glob, glob);
boost::python::object foo = glob["foo"];
std::vector<double> x;
foo.attr("bar")(x);
// Now x.size() == 1 and x[0] == 3.14

我知道这段代码不起作用,它只是我想做的事情

最好的方法是什么?

我的第一个想法是将我的x封装为另一个类VectorWrapper中的指针,但它看起来像一个丑陋的坏主意......

1 个答案:

答案 0 :(得分:1)

默认情况下,Boost.Python会创建一个副本,因为这是防止悬空引用的最安全的操作过程。但是,可以使用boost::python::ptr()boost::ref()将对C ++对象的引用传递给Python,同时保持C ++的所有权。 C ++代码应该保证C ++对象的生命周期至少和Python对象一样长。

foo.attr("bar")(boost::ref(x));
foo.attr("bar")(boost::python::ptr(&x));

上面的代码将构造一个引用std_vector_double的{​​{1}} Python对象。使用x时,如果指针为null,则生成的Python对象将为ptr()

以下是基于demonstrates使用None传递Python引用的原始问题的完整示例。

boost::ref()

#include <cmath> // std::abs #include <limits> // std::numeric_limits::epsilon #include <vector> #include <boost/python.hpp> #include <boost/python/suite/indexing/vector_indexing_suite.hpp> int main() { // Initialize Python. setenv("PYTHONPATH", ".", 1); Py_Initialize(); namespace python = boost::python; try { // Create the __main__ module. python::object main_module = python::import("__main__"); python::object main_namespace = main_module.attr("__dict__"); boost::python::class_<std::vector<double>>("std_vector_double") .def(python::vector_indexing_suite<std::vector<double>>()) ; // Run the foo.py file within the main namespace. python::exec_file("foo.py", main_namespace, main_namespace); std::vector<double> x; // Pass a reference (C++ maintains ownership) of 'x' to foo.bar(). main_namespace["foo"].attr("bar")(boost::ref(x)); // Verify 'x' was modified. assert(x.size() == 1); assert(std::abs(x[0] - 3.14) <= std::numeric_limits<double>::epsilon()); } catch (const python::error_already_set&) { PyErr_Print(); return 1; } // Do not call Py_Finalize() with Boost.Python. } 的内容是:

foo.py