Come passare un puntatore a funzione di un programma esterno in Cython
Domanda
Sto cercando di scrivere un wrapper per un programma C in modo che possa chiamare da Python. Sto usando Cython per fare questo. La funzione C richiede una funzione di callback come argomento, ma questa funzione indietro chiamata sarà noto solo in fase di esecuzione del programma pitone. Sono stato alla ricerca come fare questo e sembra non ci sia una soluzione semplice, ma il seguente sembra funzionare:
#python.py
libc = cdll.LoadLibrary("myfunc.so") #Callback function is defined in myfunc.so
....
c_wrapper(libc.fun, ...)
.
#c_wrapper.pyx
cdef extern void mainfunction(void *F, ...) #The intial C function we are wrapping
ctypedef void (*myfuncptr) ()
def c_wrapper(f, ...) # our function pointer is passed to the wrapper as a Python object
cdef myfuncptr thisfunc
thisfunc = (<myfuncptr*><size_t>addressof(f))[0]
mainfunction(thisfunc, ...)
Questo metodo funziona per funzioni C e Fortran (Io parto dal presupposto che funzionerà per la maggior parte languges compilati) e le funzioni Python (utilizzando i tipi C), ma sembra un po 'imbarazzante. C'è un modo più semplice di fare questo in Cython?
Grazie
EDIT: Non sono in grado di cambiare la libreria C che sto cercando di avvolgere
Soluzione
vi immagino siete a conoscenza di questo ?
E 'possibile chiamare il mio codice Python dal C?
Risposta: Sì, facilmente. Seguire l'esempio di Demos / richiamata / nel distribuzione del codice sorgente Cython
Quindi, sapendo che si può DLOAD tua funzione principale, prendiamo un altro approccio. Ho scritto un paio di funzioni stupide per testare questo:
/* lib.c -> lib.so */
#include <stdio.h>
void fn1(void) {
puts("Called function 1");
}
void fn2(void) {
puts("Called function 2");
}
dunque, la funzione che prende il callback
/* main.c -> main.so */
typedef void (*callback)();
void mainfunction(void *F) {
((callback)F)();
}
che può essere trasmesso direttamente da Python:
>>> from ctypes import cdll
>>> lib = cdll.LoadLibrary('./lib.so')
>>> main = cdll.LoadLibrary('./main.so')
>>> main.mainfunction(lib.fn1)
Called function 1
>>> main.mainfunction(lib.fn2)
Called function 2
E ora, cerchiamo di avvolgere una funzione Python:
>>> from ctypes import CFUNCTYPE
>>> def pyfn():
... print "Called the Python function"
...
>>> CWRAPPER = CFUNCTYPE(None)
>>> wrapped_py_func = CWRAPPER(pyfn)
>>> main.mainfunction(wrapped_py_func)
Called the Python function