如何控制 std::function 的 pybind11 包装中的参数传递策略?
How to control argument passing policy in pybind11 wrapping of std::function?
我在 c++ 中有一个 class,我正在用 pybind11 包装到 python 中。 class 有一个 std::function,我想控制如何处理该函数的参数(如 return 值策略)。我只是找不到执行此操作的语法或示例...
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 的析构函数中放置了一个打印输出,据我所知,它从未被调用过。
我在 pybind11/functional
中看不到任何允许您在调用时更改参数所有权的内容,因为使用的 struct func_wrapper
是局部函数,因此无法专门化。您可以自己提供另一个包装器,但在代码中您无法知道回调是 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);
}
好的,我想我明白了:
而不是 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));
}
}
我在 c++ 中有一个 class,我正在用 pybind11 包装到 python 中。 class 有一个 std::function,我想控制如何处理该函数的参数(如 return 值策略)。我只是找不到执行此操作的语法或示例...
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 的析构函数中放置了一个打印输出,据我所知,它从未被调用过。
我在 pybind11/functional
中看不到任何允许您在调用时更改参数所有权的内容,因为使用的 struct func_wrapper
是局部函数,因此无法专门化。您可以自己提供另一个包装器,但在代码中您无法知道回调是 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);
}
好的,我想我明白了:
而不是 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));
}
}