如何使用<double>boost::p ython通过引用将non-const std::vector传递给Python?

How to pass non-const std::vector<double> by reference to Python with boost::python?

本文关键字:vector std non-const Python 引用 double lt 何使用 gt boost ython      更新时间:2023-10-16

我希望能够给出一个空的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中的指针,但这看起来是一个丑陋的坏主意。。。

默认情况下,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));

上面的代码将构造一个引用xstd_vector_doublePython对象。使用ptr()时,如果指针为null,则生成的Python对象将为None


下面是一个基于原始问题的完整示例,演示了使用boost::ref()传递对Python的引用。

#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的内容为:

class Foo:
    def bar(self, x):
        x.append(3.14)
foo = Foo()
相关文章: