2010-02-01 9 views
5

Mam metodę wyeksportowaną do Pythona za pomocą python boost, który przyjmuje funkcję :: :: boost jako argument.Metoda Pythona w celu zwiększenia funkcji

Z tego co czytałem boost :: python powinny obsługiwać funkcję boost :: bez większego zamieszania, ale gdy próbuję wywołać funkcję z metodą python daje mi ten błąd

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) 

Wołam to z pytona z tym kodem

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

i C++, jest zdefiniowany jako

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

Naszym celem jest klasa czasowy, w którym można coś zrobić jak

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

stworzyć czasomierz, który wykonuje funcWithArgs. Dzięki wiązaniu doładowania będzie działać z praktycznie dowolną funkcją lub metodą.

Więc jaka jest składnia, której potrzebuję do boost :: python, aby zaakceptować funkcje Pythona jako funkcję boost :: function?

Odpowiedz

10

Got odpowiedź na listy Pythona, a po trochę przeróbek i dalszych badań dostałem dokładnie to, co chciałem :)

widziałem to stanowisko przed mithrandi ale nie podoba mi się pomysł posiadania zadeklarować takie funkcje. Z fantazyjnymi opakowaniami i odrobiną magii Pythona może to działać i wyglądać dobrze w tym samym czasie!

Aby rozpocząć, zakończyć swój obiekt Pythona z kodem jak ten

gdy w klasie zdefiniować metodę Podobnie jak

.def("createTimer", &createTimerWrapper, (bp::arg("interval"), bp::arg("function"), bp::arg("recurring") = false)) 

Z tą odrobiną owijki można pracować magii jak to

import MyLib 
import time 

def callMePls(): 
    print("Hello world") 
    return True 

class = MyLib.Class() 

class.createTimer(3, callMePls) 

time.sleep(1) 

Aby całkowicie naśladować C++, potrzebujemy również narzędzia boost :: bind acji, które można znaleźć tutaj: http://code.activestate.com/recipes/440557/

Dzięki temu możemy teraz zrobić coś takiego

import MyLib 
import time 

def callMePls(str): 
    print("Hello", str) 
    return True 

class = MyLib.Class() 

class.createTimer(3, bind(callMePls, "world")) 

time.sleep(1) 

EDIT:

Lubię śledzić na moje pytania, kiedy tylko mogę. Używałem tego kodu z powodzeniem przez pewien czas, ale odkryłem, że to się rozpada, gdy chcesz wziąć boost :: function w konstruktorach obiektów. Istnieje sposób, aby działał podobnie, ale nowy obiekt, który stworzysz, kończy się innym podpisem i nie będzie działał z innymi obiektami, takimi jak on.

To w końcu podsyciło mnie na tyle, że mogłem coś z tym zrobić, a ponieważ wiem więcej o boost :: python, wymyśliłem całkiem niezłe rozwiązanie "pasuje do wszystkich" za pomocą konwerterów. Ten kod skonwertuje pytona wywoływanego na boost :: python < bool()> obiekt, można go łatwo zmodyfikować, aby przekonwertować go na inne funkcje doładowania.

// 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; 
    } 
}; 

Następnie w kodzie init tj BOOST_PYTHON_MODULE(), po prostu zarejestrować typ tworząc struct

BOOST_PYTHON_MODULE(Foo) 
{ 
    // Register function converter 
    BoostFunc_from_Python_Callable(); 
Powiązane problemy