调用boost::python::call的更智能方式

Smarter way of calling boost::python::call?

本文关键字:智能 方式 call boost python 调用      更新时间:2023-10-16

我已经编写了一个小类方法,它通过boost::python从C++调用python函数,并且我已经观察到纯python的速度有了很好的改进:

namespace bp = boost::python;
double pyf::eval(double * const x) const
{
  bp::list lx;
  for (size_t i = 0; i < this->get_n(); i++)
    lx.append(x[i]);
  return bp::call<double>(pycb_, lx);
}

pycb_是我的PyObject*回调函数。

我的问题是:你知道从double *指针创建boost::python::list的更聪明的方法吗?我目前的解决方案很虚,但我发现boost::python文档很难理解,而且缺乏具体的示例,所以欢迎您的经验!

仅供参考,我使用的是相对较旧的Boost版本(1.41)。此外,我的包的其余部分依赖于boost,我更喜欢使用boost::python,避免添加第三方pkg。

据我所知,迭代是从该类型的源代码填充Boost.Python list的唯一方法。删除部分样板代码的替代迭代解决方案包括使用Boost.ForEach或std::for_each算法。

例如,以下两个片段等效于原始代码:

double pyf::eval(double * const x) const
{
  bp::list lx;
  BOOST_FOREACH(double& value, boost::make_iterator_range(x, x + this->get_n()))
    lx.append(value);
  return bp::call<double>(pycb_, lx);
}

double pyf::eval(double * const x) const
{
  bp::list lx;
  std::for_each(x, x + this->get_n(), 
                boost::bind(&bp::list::append<double>, &lx, _1));
  return bp::call<double>(pycb_, lx);
}

下面是一个嵌入式Python的基本示例,展示了这两种方法:

#include <algorithm>
#include <iostream>
#include <boost/array.hpp>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/python.hpp>
int main()
{
  Py_Initialize();
  namespace python = boost::python;
  try
  {
    python::object main = python::import("__main__");
    // Add the verbose_sum function to main.
    python::exec(
      "def verbose_sum(x):n"
      "    print xn"
      "    return sum(x)n"
      "n", main.attr("__dict__"));
    // Mockup data.
    PyObject* callback = python::object(main.attr("verbose_sum")).ptr();
    boost::array<double, 5> x_array = {{ 1, 2, 3, 4, 5 }};
    double* const x = &x_array[0];
    const std::size_t n = x_array.size();
    // Range iterator.
    {
      python::list x_list;
      BOOST_FOREACH(double& value, boost::make_iterator_range(x, x + n))
        x_list.append(value);
      std::cout << python::call<double>(callback, x_list) << std::endl;
    }
    // Algorithm with binding.
    {
      python::list x_list;
      std::for_each(x, x + n, 
                    boost::bind(&python::list::append<double>, &x_list, _1));
      std::cout << python::call<double>(callback, x_list) << std::endl;
    }
  }
  catch (python::error_already_set&)
  {
    PyErr_Print();
  }
}

输出:

[1.0, 2.0, 3.0, 4.0, 5.0]
15
[1.0, 2.0, 3.0, 4.0, 5.0]
15