Как управлять политикой передачи аргументов в оболочке pydbind11 std :: function? - PullRequest
1 голос
/ 07 февраля 2020

У меня есть класс в c ++, который я обертываю в python с помощью pybind11. Этот класс имеет функцию std :: function, и я хотел бы контролировать, как обрабатываются аргументы этой функции (например, политики возвращаемых значений). Я просто не могу найти синтаксис или примеры для этого ...

class N {
public:
   using CallbackType = std::function<void(const OtherClass*)>;
   N(CallbackType callback): callback(callback) { }
   CallbackType callback;

   void doit() {
      OtherClass * o = new OtherClass();
      callback(o);
   }
}

, завернутый в

py::class_<OtherClass>(...standard stuff...);

py::class_<N>(m, "N")
   .def(py::init<N::CallbackType>(),
      py::arg("callback"));

У меня все работает: я могу сделать это в python:

def callback(o):
   dosomethingwith(o)

k = N(callback)

, но я бы хотел иметь возможность контролировать то, что происходит, когда вызывается callback(o); - будет ли python тогда вступать во владение обернутой переменной o или нет, в основном.


Я положил распечатку в деструктор OtherClass, и, насколько я могу судить, она никогда не вызывается.

Ответы [ 2 ]

1 голос
/ 11 февраля 2020

ОК, думаю, я понял это:

Вместо std :: function, используйте pybind11 :: function:

using CallbackType = pybind11::function

, а затем

void doit(const OtherClass &input) {
        if (<I want to copy it>) {
            callback(pybind11::cast(input, pybind11::return_value_policy::copy));
        } else {
            callback(pybind11::cast(input, pybind11::return_value_policy::reference));     
        }
   }
1 голос
/ 08 февраля 2020

В pybind11/functional я не вижу ничего, что позволяло бы вам изменять владельца параметров в точке вызова, так как struct func_wrapper используется как функция local, поэтому не может быть специализированной. Вы могли бы предоставить другую обертку самостоятельно, но в коде вы не можете знать, является ли обратный вызов функцией Python или связанной функцией C ++ (ну, технически вы можете это сделать, если эта связанная функция C ++ связана с pybind11, но вы можете ' не знаю в общем). Если функция C ++, то изменение владельца Python в обертке было бы неправильным решением, поскольку временный прокси-сервер может уничтожить объект, даже если его полезная нагрузка сохранена обратным вызовом C ++.

есть контроль над реализацией class N? Причина в том, что при использовании std::shared_ptr все ваши проблемы владения будут автоматически испаряться, независимо от того, является ли функция обратного вызова C ++ или Python и сохраняет ли она аргумент или нет. Будет работать так, расширив ваш пример выше:

#include <pybind11/pybind11.h>
#include <pybind11/functional.h>

namespace py = pybind11;

class OtherClass {};

class N {
public:
   using CallbackType = std::function<void(const std::shared_ptr<OtherClass>&)>;
   N(CallbackType callback): callback(callback) { }
   CallbackType callback;

   void doit() {
      auto o = std::make_shared<OtherClass>();
      callback(o);
   }
};

PYBIND11_MODULE(example, m) {
    py::class_<OtherClass, std::shared_ptr<OtherClass>>(m, "OtherClass");

    py::class_<N>(m, "N")
       .def(py::init<N::CallbackType>(), py::arg("callback"))
       .def("doit", &N::doit);
}
...