python - boost python返回包含自定义类型的元组

标签 python c++ boost tuples boost-python

我有一个 C++ myObject 类,我使用包装器结构通过 boost python 公开它:

struct myObjectWrapper{
   static tuple compute(myObject& o,const Container& x0, const double& t0, Container& x){
      double t;
      int stat = o.evaluate(x0,t0,x,t);
      return make_tuple(stat,t);
   }
}

BOOST_PYTHON_MODULE(myModule)
{
   // not shown here is code to expose Container class

   class_<myObject>("MyObject")
      .def("compute",&myObjectWrapper::compute)
   ;
}

容器当前定义为:

typedef std::valarray<double> Container

并暴露于 python。

现在在 python 中我可以做到。

x = Container()
(status,t) = obj.compute(Container([0.,0.,0.]),0.0,x)
print status, t, x[0]

这不是很pythonic。我更愿意这样做:

(status,t,x) = obj.compute(Container([0.,0.,0.]),0.0)
print status, t, x[0]    

我可以用 python 编写额外的包装器,但我宁愿避免添加更多包装器。

以下代码无法编译:

struct myObjectWrapper{
   static tuple compute(myObject& o,const Container& x0, const double& t0){
      double t;
      Container x;
      int stat = o.evaluate(x0,t0,x,t);
      return make_tuple(stat,t,x);
   }
}

此外,我更愿意窃取局部变量 x 的内容并让 python 管理它而不是复制它:

return make_tuple(stat,t,std::move(x));

我如何实现这一目标?

最佳答案

简而言之,在免费存储上分配包装器并使用 manage_new_object结果转换为将所有权转移到 Python 对象。这将导致 Boost.Python 在构造 Python 对象时复制指针,而不是复制指针。有关详细信息,请参阅 this回答。

这是一个将所有权转移到 Python 对象的辅助函数:

/// @brief Transfer ownership to a Python object.  If the transfer fails,
///        then object will be destroyed and an exception is thrown.
template <typename T>
boost::python::object transfer_to_python(T* t)
{
  // Transfer ownership to a smart pointer, allowing for proper cleanup
  // incase Boost.Python throws.
  std::unique_ptr<T> ptr(t);

  // Use the manage_new_object generator to transfer ownership to Python.
  namespace python = boost::python;
  typename python::manage_new_object::apply<T*>::type converter;

  // Transfer ownership to the Python handler and release ownership
  // from C++.
  python::handle<> handle(converter(*ptr));
  ptr.release();

  return python::object(handle);
}

可以按如下方式使用它:

boost::python::tuple myObjectWrapper::compute(
  myObject& o, const Container& x0, const double& t0)
{
  auto x1 = std::make_unique<container>();
  double t1 = 0;
  int stat = self.evaluate(x0, t0, *x1, t1);
  return boost::python::make_tuple(stat, t1, transfer_to_python(x1.release()));
}

这是一个基于原始问题的完整示例 demonstrates使用 transfer_to_python 辅助函数。

#include <boost/python.hpp>
#include <cassert>
#include <memory> // std::unique_ptr

// Mock legacy API.
struct container
{
  container() {}
  container(boost::python::object) {}

  container(const container&)
  {
    // For this example, guarantee copy is not made.
    assert(false);
   }
};

struct my_object
{
  int evaluate(container&, double&, container&, double&) { return 42; }
};

/// @brief Transfer ownership to a Python object.  If the transfer fails,
///        then object will be destroyed and an exception is thrown.
template <typename T>
boost::python::object transfer_to_python(T* t)
{
  // Transfer ownership to a smart pointer, allowing for proper cleanup
  // incase Boost.Python throws.
  std::unique_ptr<T> ptr(t);

  // Use the manage_new_object generator to transfer ownership to Python.
  namespace python = boost::python;
  typename python::manage_new_object::apply<T*>::type converter;

  // Transfer ownership to the Python handler and release ownership
  // from C++.
  python::handle<> handle(converter(*ptr));
  ptr.release();

  return python::object(handle);
}

// API wrapper.
boost::python::tuple my_object_compute(
  my_object& self, container& x0, double t0)
{
  auto x1 = std::make_unique<container>();
  double t1 = 21;
  int stat = self.evaluate(x0, t0, *x1, t1);
  return boost::python::make_tuple(stat, t1, transfer_to_python(x1.release()));
}

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;

  python::class_<container>("Container")
    .def(python::init<python::object>())
    ;

  python::class_<my_object>("MyObject")
    .def("compute", &my_object_compute)
    ;
}

交互使用:

>>> import example
>>> my_object = example.MyObject()
>>> status, t, x = my_object.compute(example.Container([1, 2, 3]), 4)
>>> assert(status == 42)
>>> assert(t == 21)
>>> assert(isinstance(x, example.Container))

关于python - boost python返回包含自定义类型的元组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35957073/

相关文章:

python - 如何做 while() "pythonic way"

python - 当使用@click.option 将命令行参数传递给函数时,如何返回值?

c++ - 如何获取当前控制台背景和文本颜色?

c++ - 错误 LNK2005 : already defined on including a header file twice

c++ - 将类对象作为参数传递给 boost::thread

python - TensorFlow:有没有办法测量模型的 FLOPS?

python - 在 Tensorflow 中,获取图中所有张量的名称

c++ - 简单程序中的零错误除法

c++ - 为什么boost需要&vector[0]?

c++ - 如果服务器未运行,async_connect 成功