oggetti Python come datiutente nelle funzioni ctypes callback
Domanda
La funzione myfunc
C opera su un grande blocco di dati. I risultati vengono restituiti in blocchi ad una funzione di callback:
int myfunc(const char *data, int (*callback)(char *result, void *userdata), void *userdata);
Utilizzando ctypes , non è un grosso problema per chiamare myfunc
dal codice Python, e per avere i risultati da restituire a una funzione di callback Python. Questo lavoro di richiamata bene.
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)
Ma, esiste un modo per dare un oggetto Python (ad esempio una lista) come userdata alla funzione di callback? Al fine di riporre i pezzi di risultato, mi piacerebbe fare per esempio:.
def mycb(result, userdata):
userdata.append(result)
userdata=[]
Ma non ho idea di come lanciare la lista Python per un c_void_p, in modo che possa essere utilizzato nella chiamata a myfunc.
La mia soluzione attuale è quella di implementare una lista concatenata come struttura ctypes, che è piuttosto ingombrante.
Soluzione
Credo che si potrebbe utilizzare il Python API C di farlo ... forse si potrebbe usare un puntatore PyObject.
modifica : Come l'op sottolineato nei commenti, c'è già digitare facilmente disponibili in ctypes un py_object
, quindi la soluzione è quello di creare prima un oggetto ctypes.py_object
dalla lista Python e poi colata a c_void_p
farla passare come argomento alla funzione C (penso che questo passaggio potrebbe non essere necessario come parametro digitato come void*
dovrebbe accettare qualsiasi puntatore, e sarebbe più veloce per passare solo un byref
). Nella richiamata, al contrario i passaggi sono fatto (casting dal puntatore nullo a un puntatore a py_object
e quindi ottenere il valore dei contenuti).
Una soluzione potrebbe essere quella di utilizzare una chiusura per la vostra funzione di callback in modo che già conosce, in cui elencare deve aggiungere le voci ...
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)))