zeb*_*zeb 1 c++ python boost boost-python c++11
我有一个包含std :: function属性的类.我使用成员函数设置此属性的值,因此该类看起来像这样:
class ClassName
{
public:
void SetCallbackFunction(std::function<void (int i)> callbackFun) {
m_callbackFunction = callbackFun;
}
protected:
std::function<void (int i)> m_callbackFunction;
};
Run Code Online (Sandbox Code Playgroud)
我需要将这个类暴露给Python,当然,我需要公开该SetCallbackFunction函数.我怎么能用boost :: python做到这一点?
由于Python对象都是Callable和CopyConstructible,最简单的方法是公开一个辅助函数,因为SetCallbackFunction它接受a boost::python::object,然后委托给实际的SetCallbackFunction函数:
void ClassName_SetCallbackFunction_aux(ClassName& self, boost::python::object object)
{
self.SetCallbackFunction(object);
}
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
python::class_<ClassName>("ClassName", python::init<>())
.def("set_callback", &ClassName_SetCallbackFunction_aux)
// ...
;
}
Run Code Online (Sandbox Code Playgroud)
当ClassName::SetCallbackFunction直接暴露给Python并调用时,Boost.Python将在运行时搜索其注册表以找到from-Python转换器std::function<void (int)>.由于此转换尚未明确注册,Boost.Python将无法调度函数调用.辅助函数避免了这个运行时转换检查并std::function<void (int)>从a 构造了一个对象boost::python::object,因为boost::python::object它既是Callable又是CopyConstructible.
下面是一个演示使用辅助函数将Python对象分配为回调的示例:
#include <functional> // std::function
#include <boost/python.hpp>
// Legacy API.
class spam
{
public:
void SetCallbackFunction(std::function<void (int)> callback)
{
callback_ = callback;
}
void perform(int x)
{
callback_(x);
}
private:
std::function<void (int)> callback_;
};
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
// Expose spam.
python::class_<spam>("Spam", python::init<>())
// Use an auxiliary function to set Python callbacks.
.def("set_callback", +[](spam& self, boost::python::object object) {
self.SetCallbackFunction(object);
})
.def("perform", &spam::perform)
;
}
Run Code Online (Sandbox Code Playgroud)
互动用法:
>>> import example
>>> called = False
>>> def perform_x(x):
... assert(42 == x)
... global called
... called = True
...
>>> spam = example.Spam()
>>> spam.set_callback(perform_x)
>>> assert(not called)
>>> spam.perform(42)
>>> assert(called) # Verify callback was invoked
>>> spam.set_callback(lambda: None)
>>> try:
... spam.perform(42)
... assert(False) # Verify callback fails (the lambda accepts no args)
... except TypeError:
... pass
...
Run Code Online (Sandbox Code Playgroud)