使用pybind11从c ++调用Python函数

时间:2017-03-01 01:51:23

标签: c++ pybind11

我试图使用main()从包含Pybind11函数的C ++代码调用python函数。但我发现很少有参考资料。大多数现有文档都讨论了相反的方向,即从Python调用C ++。

有没有完整的例子说明如何做到这一点?我找到的唯一参考是:https://github.com/pybind/pybind11/issues/30

但它的信息很少。

2 个答案:

答案 0 :(得分:5)

你的问题的答案实际上有两个部分:一个是关于从C ++调用Python函数,另一个是关于嵌入解释器。

调用pybind11中的函数只是将该函数转换为pybind11::object变量,您可以在该变量上调用operator()来尝试调用该对象。 (它不一定是函数,只是可调用的东西:例如,它也可以是具有__call__方法的对象)。例如,要从C ++代码中调用math.sqrt(2),您可以使用:

auto math = py::module::import("math");
auto resultobj = math.attr("sqrt")(2);
double result = resultobj.cast<double>();

或者你可以将它全部浓缩为:

double result = py::module::import("math").attr("sqrt")(2).cast<double>();

问题的第二部分涉及如何从C ++可执行文件中执行此操作。在构建可执行文件时(即当您的C ++代码包含main()时),您必须先将Python解释器嵌入到二进制文件中,然后才能对Python执行任何操作(如调用Python函数)。

嵌入式支持是当前pybind11 master分支中添加的新功能(将成为2.2版本)。这是启动嵌入式Python解释器并调用Python函数(math.sqrt)的基本示例:

#include <pybind11/embed.h>
#include <iostream>

namespace py = pybind11;

int main() {
    py::scoped_interpreter python;

    auto math = py::module::import("math");
    double root_two = math.attr("sqrt")(2.0).cast<double>();

    std::cout << "The square root of 2 is: " << root_two << "\n";
}

输出:

The square root of 2 is: 1.41421

分别在http://pybind11.readthedocs.io/en/master/advanced/pycpp/object.htmlhttp://pybind11.readthedocs.io/en/master/advanced/embedding.html提供了有关调用函数和嵌入的更多示例和文档。

答案 1 :(得分:0)

Jasons的答案很合理,但是我想添加一个稍微复杂(干净)的示例,该示例使用numpy输入调用python方法。 我想展示两点:

  1. 我们可以使用py::objectpy::function投射到py::reinterpret_borrow<py::function>
  2. 我们可以输入一个std::vector,它会自动转换为numpy.array

请注意,用户有责任确保PyModule.attr实际上是python函数。另外请注意,类型转换可用于多种c++类型(有关详细信息,请参见here)。

在此示例中,我想将scipy.optimize.minimize方法与从c ++接口提供的起点x0一起使用。

#include <iostream>
#include <vector>
#include <pybind11/pybind11.h>
#include <pybind11/embed.h>  // python interpreter
#include <pybind11/stl.h>  // type conversion

namespace py = pybind11;

int main() {
  std::cout << "Starting pybind" << std::endl;
  py::scoped_interpreter guard{}; // start interpreter, dies when out of scope

  py::function min_rosen =
      py::reinterpret_borrow<py::function>(   // cast from 'object' to 'function - use `borrow` (copy) or `steal` (move)
          py::module::import("py_src.exec_numpy").attr("min_rosen")  // import method "min_rosen" from python "module"
      );

  py::object result = min_rosen(std::vector<double>{1,2,3,4,5});  // automatic conversion from `std::vector` to `numpy.array`, imported in `pybind11/stl.h`
  bool success = res.attr("success").cast<bool>();
  int num_iters = res.attr("nit").cast<int>();
  double obj_value = res.attr("fun").cast<double>();
}

使用python脚本py_src/exec_numpy.py

import numpy as np
from scipy.optimize import minimize, rosen, rosen_der

def min_rosen(x0):
    res = minimize(rosen, x0)
    return res

希望这对某人有帮助!