2010-03-18 18 views
10

La función C myfunc opera en una gran cantidad de datos. Los resultados se devuelven en trozos a una función de devolución de llamada:Objetos de Python como datos de usuario en las funciones de devolución de llamada ctypes

int myfunc(const char *data, int (*callback)(char *result, void *userdata), void *userdata); 

Usando ctypes, que no es gran cosa para llamar myfunc de código Python, y para tener los resultados que se devuelven a una función de devolución de llamada Python. Esta devolución de llamada funciona bien.

myfunc = mylib.myfunc 
myfunc.restype = c_int 
myfuncFUNCTYPE = CFUNCTYPE(STRING, c_void_p) 
myfunc.argtypes = [POINTER(c_char), callbackFUNCTYPE, c_void_p] 

def mycb(result, userdata): 
    print result 
    return True 

input="A large chunk of data." 
myfunc(input, myfuncFUNCTYPE(mycb), 0) 

Pero, ¿hay alguna manera de dar un objeto de Python (por ejemplo una lista) como datos de usuario a la función de devolución de llamada? Con el fin de almacenar lejos los trozos de resultado, me gustaría hacer por ejemplo:

def mycb(result, userdata): 
    userdata.append(result) 

userdata=[] 

Pero no tengo idea de cómo emitir la lista de Python a un c_void_p, de modo que pueda ser utilizado en la llamada a MyFunc .

Mi solución actual es implementar una lista vinculada como una estructura de tipos, que es bastante engorrosa.

Respuesta

3

Supongo que podría usar el Python C API para hacer eso ... quizás podría usar un puntero PyObject.

edición: A medida que el op señaló en los comentarios, ya hay un tipo py_object fácilmente disponibles en ctypes, por lo que la solución es crear primero un objeto ctypes.py_object de la lista de pitón y luego se convierte para c_void_p para pasarlo como argumento para la función C (creo que este paso podría ser innecesario ya que un parámetro escrito como void* debería aceptar cualquier puntero, y sería más rápido pasar solo un byref). En la devolución de llamada, los pasos inversos se realizan (lanzando desde el puntero de vacío a un puntero a py_object y luego obteniendo el valor de los contenidos).

Una solución alternativa podría ser el uso de un cierre para su función de devolución por lo que ya se sabe en qué lista se tiene que añadir los artículos ...

myfunc = mylib.myfunc 
myfunc.restype = c_int 
myfuncFUNCTYPE = CFUNCTYPE(STRING) 
myfunc.argtypes = [POINTER(c_char), callbackFUNCTYPE] 


def mycb(result, userdata): 
    userdata.append(result) 

input="A large chunk of data." 
userdata = [] 
myfunc(input, myfuncFUNCTYPE(lambda x: mycb(x, userdata))) 
+0

Bueno, lo bueno de ctypes es que todo puede ser hecho en Python simple Entonces, la API de Python C parece estar un paso atrás. ¿O me estoy perdiendo algo? – flight

+0

Quise decir que la opción podría ser crear un proxy ctypes de una estructura C-API PyObject, que debería ser la representación interna de cualquier objeto Python y pasándolo ... – fortran

+0

Extraño. Su solución con un cierre funciona bien en Linux, pero el mismo programa falla en Windows. – flight

Cuestiones relacionadas