вызвать функцию Python из c ++ с помощью pybind11

Я пытаюсь вызвать функцию Python из кода C ++, который содержит функцию main(), используя Pybind11. Но я обнаружил, что доступных ссылок очень мало. В большинстве существующих документов говорится об обратном направлении, то есть о вызове C ++ из Python.

Есть ли полный пример, показывающий, как это сделать? Единственная найденная мной ссылка: https://github.com/pybind/pybind11/issues/30 < / а>

Но информации очень мало.


person stanleyli    schedule 01.03.2017    source источник


Ответы (2)


Ответ на ваш вопрос состоит из двух частей: одна касается вызова функции Python из C ++, другая - встраивания интерпретатора.

Вызов функции в pybind11 - это просто вопрос помещения этой функции в переменную pybind11::object, для которой вы можете вызвать operator(), чтобы попытаться вызвать объект. (Это не обязательно должна быть функция, а просто что-то вызываемое: например, это также может быть объект с __call__ методом). Например, чтобы вызвать math.sqrt(2) из кода C ++, вы должны использовать:

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.html и http://pybind11.readthedocs.io/en/master/advanced/embedding.html соответственно.

person Jason Rhinelander    schedule 14.07.2017

Ответ Джейсона в значительной степени уместен, но я хочу добавить немного более сложный (и чистый) пример вызова метода python с вводом numpy. Я хочу выделить два момента:

  1. Мы можем преобразовать py::object в py::function, используя py::reinterpret_borrow<py::function>
  2. Мы можем ввести std::vector, который автоматически преобразуется в numpy.array

Обратите внимание, что пользователь несет ответственность за то, чтобы PyModule.attr на самом деле была функцией python. Также обратите внимание, что преобразование типов работает для большого количества c++ типов (см. здесь для подробностей).

В этом примере я хочу использовать метод scipy.optimize.minimize с начальной точкой x0, которая предоставляется из интерфейса C ++.

#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 = result.attr("success").cast<bool>();
  int num_iters = result.attr("nit").cast<int>();
  double obj_value = result.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

Надеюсь, это кому-то поможет!

person Romeo Valentin    schedule 12.07.2019
comment
Привет, я пытаюсь использовать ваш код, но получаю сообщение: исключение Microsoft C ++: pybind11 :: error_already_set в памяти - person Ziri; 27.12.2019
comment
В последних трех строках кода C ++ есть res.attr, но это должно быть result.attr. - person AlDanial; 04.02.2020
comment
Есть ли способ избежать копирования данных из контейнера STL в numpy.array во время автоматического преобразования? Что-то вроде создания объекта Python, который указывает на память контейнера STL ... - person Rackbox; 04.06.2020
comment
Я пытался найти способ избежать копий из STL в Python, но не нашел. - person Romeo Valentin; 06.06.2020
comment
У меня немного другая трудность, но, возможно, вы мне поможете. Я пытаюсь использовать код C ++ из Python, но когда я добавляю стороннюю библиотеку в свой код C ++, я получаю ImportError: DLL load failed while importing. Кажется, я не понимаю, как это сделать где угодно. - person mquasar; 17.03.2021