2010-02-01 46 views
5

我有一個方法導出到Python使用boost python,它需要一個boost :: function作爲參數。Python的方法來提升功能

從我讀過的boost ::蟒蛇應該支持的boost ::功能,無需大驚小怪,但是當我嘗試調用函數與蟒蛇方法它給了我這個錯誤

Boost.Python.ArgumentError: Python argument types in 
    Class.createTimer(Class, int, method, bool) 
did not match C++ signature: 
    createTimer(class Class {lvalue}, unsigned long interval, 
    class boost::function<bool _cdecl(void)> function, bool recurring=False) 

我打電話它從蟒與此代碼

self.__class.createTimer(3, test.timerFunc, False) 

和在C++中它被定義爲

boost::int32_t createTimer(boost::uint32_t interval, boost::function< bool() > function, bool recurring = false); 

這裏的目標是一個定時器類,我可以做這樣的事情

class->createTimer(3, boost::bind(&funcWithArgs, arg1, arg2)) 

創建執行funcWithArgs一個計時器。多虧了boost綁定,它可以和任何函數或方法一起工作。

那麼我需要什麼語法來使用boost :: python來接受我的python函數作爲boost :: function?

回答

10

得到了蟒蛇郵件列表上的回答,有點改造和更多的研究,我正是我想要:)

我沒有看到mithrandi之前的文章,但我並不想再的主意宣佈這樣的功能。隨着一些花哨的包裝和一點蟒蛇魔術這可以工作,並在同一時間看起來不錯!

開始,包你的Python對象有這樣的代碼

當在類中定義,像這樣

.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++,我們還需要一個boost :: bind工具通貨膨脹可以在這裏找到: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 :: function的時候,這會崩潰。 有一種方法可以使它與此類似工作,但是您構造的新對象最終具有不同的簽名,並且不會與其他對象一起使用。

這終於搞砸了我足以做些什麼,因爲我知道更多關於boost :: python現在我想出了一個很好的'適合所有'使用轉換器的解決方案。 這裏的代碼將一個python callable轉換爲一個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(); 
註冊類型