在python邮件列表上得到了一个答案,经过一番修改和更多的研究,我得到了我想要的东西:)
我在密特拉ndi之前看到过这个帖子,但是我不喜欢这样声明函数的想法。有了一些精美的包装纸和一点巨蟒的魔力,这可以工作,同时看起来很好!
首先,用这样的代码包装您的python对象
struct timer_func_wrapper_t
{
timer_func_wrapper_t( bp::object callable ) : _callable( callable ) {}
bool operator()()
{
// These GIL calls make it thread safe, may or may not be needed depending on your use case
PyGILState_STATE gstate = PyGILState_Ensure();
bool ret = _callable();
PyGILState_Release( gstate );
return ret;
}
bp::object _callable;
};
boost::int32_t createTimerWrapper( Class* class, boost::uint64_t interval, bp::object function, bool recurring = false )
{
return class->createTimer( interval, boost::function<bool ()>( timer_func_wrapper_t( function ) ), recurring );
}
在类中,像这样定义方法
.def( "createTimer", &createTimerWrapper, ( bp::arg( "interval" ), bp::arg( "function" ), bp::arg( "recurring" ) = false ) )
有了这个小包装,你就可以像这样神奇地工作了。
import MyLib
import time
def callMePls():
print( "Hello world" )
return True
class = MyLib.Class()
class.createTimer( 3, callMePls )
time.sleep( 1 )
为了完全模拟C++,我们还需要一个Boosix::Band实现,可以在这里找到:
http://code.activestate.com/recipes/440557/
有了这个,我们现在可以做类似的事情了
import MyLib
import time
def callMePls( str ):
print( "Hello", str )
return True
class = MyLib.Class()
class.createTimer( 3, bind( callMePls, "world" ) )
time.sleep( 1 )
编辑:
我喜欢尽可能地跟进我的问题。有一段时间我成功地使用了这段代码,但我发现当您想在对象构造函数中使用boost::函数时,这段代码会崩溃。
有一种方法可以使它与此类似,但是您构造的新对象最终会有一个不同的签名,并且不会与其他对象(如它本身)一起工作。
这终于让我烦得不知所措了,既然我对boost::python了解得更多,现在我就想出了一个使用转换器的非常好的“适合所有人”的解决方案。
这里的代码将把一个可调用的python转换成boost::python<bool()>对象,可以很容易地修改它来转换成其他boost函数。
// Wrapper for timer function parameter
struct timer_func_wrapper_t
{
timer_func_wrapper_t( bp::object callable ) : _callable(callable) {}
bool operator()()
{
return _callable();
}
bp::object _callable;
};
struct BoostFunc_from_Python_Callable
{
BoostFunc_from_Python_Callable()
{
bp::converter::registry::push_back( &convertible, &construct, bp::type_id< boost::function< bool() > >() );
}
static void* convertible( PyObject* obj_ptr )
{
if( !PyCallable_Check( obj_ptr ) ) return 0;
return obj_ptr;
}
static void construct( PyObject* obj_ptr, bp::converter::rvalue_from_python_stage1_data* data )
{
bp::object callable( bp::handle<>( bp::borrowed( obj_ptr ) ) );
void* storage = ( ( bp::converter::rvalue_from_python_storage< boost::function< bool() > >* ) data )->storage.bytes;
new (storage)boost::function< bool() >( timer_func_wrapper_t( callable ) );
data->convertible = storage;
}
};
然后在初始化代码中,即boost_python_module(),只需通过创建结构来注册类型。
BOOST_PYTHON_MODULE(Foo)
{
// Register function converter
BoostFunc_from_Python_Callable();