1

I am able to get normal callbacks from native to Cython.

But, how do i set a member function to be callback in cython.

My sampleCallback.h file is :

 namespace mango {
 class sampleCalls { 
 public:
     typedef void (*Callback)(char *name);

     sampleCalls(Callback method, char *name);
     void execute();
 private:
     Callback _method;
     char *_key;
 }; }

And my sampleCallback.cpp file contains simple implementation :

 namespace mango {
        sampleCalls::sampleCalls(Callback method, char *name) {
                _method = method;
                _key = name;
        };
        void sampleCalls::execute()
        {
                return _method(_key);
        };
}

Now i have written a very simple cython wrapper callback.pyx:

ctypedef void (*Callback)(char *name)

cdef extern from "sampleCallback.h" namespace "mango" :
        cdef cppclass sampleCalls:
                sampleCalls(Callback method, char *name)
                void execute()

cdef void callbackCY(char* name):
        print "I AM ", name

cdef class pyCallback:
    cdef sampleCalls* sc

    def __init__(self):
            self.sc = new sampleCalls(callbackCY, "BATMAN")

    def  execute(self):
            self.sc.execute()

This builds and works fine when i run a simple python code :

import callback
cb = callback.pyCallback()
cb.execute()

This works just fine and outputs :: I AM BATMAN

But this is not what i want. I want the callback function to be a part of the cython defined class, so i implemented the class something like this :

cdef class pyCallback:
    cdef sampleCalls* sc

    def __init__(self):
        self.sc = new sampleCalls(cb, "BATMAN")

    def  execute(self):
        self.sc.execute()

    cdef void cb(self, char* name):
        print name, " WINS"

This does not work of course as callback prototype do not match.

WHAT IS THE PROPER WAY TO DO IT?

I also tried std::bind something like this ::

cdef place1 "std::placeholder1"
cdef bind_py "std::bind"

cdef class pyCallback:
    cdef sampleCalls* sc

    def __init__(self):
        self.sc = new sampleCalls(bind_py(self.cb, self, place1),     "BATMAN")

This does not work either. The error ::

Error compiling Cython file:
------------------------------------------------------------
...
cdef class pyCallback:
    cdef sampleCalls* sc

    def __init__(self):
            self.sc = new sampleCalls(bind_py(self.cb, self, place1), "BATMAN")
                                   ^
------------------------------------------------------------

callback.pyx:19:40: Cannot convert 'void (pyCallback, char *)' to Python object

Error compiling Cython file:
------------------------------------------------------------
...
cdef class pyCallback:
    cdef sampleCalls* sc

    def __init__(self):
            self.sc = new sampleCalls(bind_py(self.cb, self, place1), "BATMAN")
                              ^
------------------------------------------------------------

callback.pyx:19:35: Cannot convert Python object to 'Callback'

How can i get this done ?? Please help.

Innat
  • 16,113
  • 6
  • 53
  • 101
wolv3r1n3
  • 63
  • 6
  • [See the second part of this answer](https://stackoverflow.com/questions/34878942/using-function-pointers-to-methods-of-classes-without-the-gil/34900829#34900829) for an approach that uses Ctypes. If you can change the signature to a C++ `std::function` then see [this answer](https://stackoverflow.com/a/46204346/4657412) – DavidW May 14 '18 at 17:09
  • Hello DavidW, I tried to implement as per the second part of your answer. ftype = ctypes.CFUNCTYPE(c_void, POINTER(c_char)) f = ftype(self.internalCallback) But am not sure what to do with the 3rd line "cdef someFunctionPointer cy_f_ptr = (ctypes.addressof(f))[0]" How do i declare this ? What should i replace "someFunctionPointer" with ? It is supposed to be 'type identifier' right ? – wolv3r1n3 May 31 '18 at 07:07
  • "someFunctionPointer" is a `ctypedef` of a C function pointer. e.g. do `ctypedef void (*someFunctionPointer)(char*)` to make `someFunctionPointer` be a pointer to a function that accepts a char* and returns nothing. – DavidW Jun 01 '18 at 20:01

0 Answers0