2010-03-18 8 views
10

Die C-Funktion myfunc arbeitet auf einem größeren Datenblock. Die Ergebnisse sind in Blöcken auf eine Callback-Funktion zurückgegeben:Python-Objekte als Benutzerdaten in Ctypes-Callback-Funktionen

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

Mit ctypes, es ist keine große Sache myfunc von Python-Code aufzurufen und die Ergebnisse in eine Python-Callback-Funktion zurückgegeben zu haben ist. Dieser Rückruf funktioniert gut.

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) 

Aber ist es eine Möglichkeit, ein Python-Objekt (zB eine Liste) als Benutzerdaten an die Rückruffunktion zu geben? Um das Ergebnis Brocken weg zu speichern, würde ich tun, zum Beispiel mag:

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

userdata=[] 

Aber ich habe keine Ahnung, wie die Python-Liste in eine c_void_p zu werfen, so dass es in dem Aufruf verwendet werden kann, um MyFunc .

Meine aktuelle Problemumgehung ist es, eine verkettete Liste als Ctypes-Struktur zu implementieren, die ziemlich umständlich ist.

Antwort

3

Ich denke, Sie könnten die Python C API verwenden, um das zu tun ... vielleicht könnten Sie einen PyObject-Zeiger verwenden.

bearbeiten: Wie der op in den Kommentaren darauf hingewiesen, gibt es bereits einen py_object Typen in ctypes leicht verfügbar, so dass die Lösung ist zunächst ein ctypes.py_object Objekt aus der Python-Liste zu erstellen und es dann zu c_void_p Gießen es passieren als Argument für die C-Funktion (ich denke, dieser Schritt könnte unnötig sein, da ein Parameter wie void* jeden Zeiger akzeptieren würde, und es wäre schneller, nur eine byref zu übergeben). Im Callback werden die umgekehrten Schritte ausgeführt (Umwandlung vom leeren Zeiger auf einen Zeiger auf py_object und dann Abrufen des Werts des Inhalts).

konnte Eine Abhilfe, einen Verschluss für Ihre Callback-Funktion zu verwenden, damit es in dem bereits weiß, geben Sie es die Elemente anhängen hat ...

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

Nun, das ist das Schöne an ctypes, dass alles sein kann in schlichtem Python gemacht. Daher scheint die Python C API ein Schritt zurück zu sein. Oder fehlt mir etwas? – flight

+0

Ich meine, die Option könnte einen Ctypes-Proxy einer C-API PyObject-Struktur erstellen, die die interne Repräsentation jedes Python-Objekts sein und es weitergeben sollte ... – fortran

+0

Seltsam. Ihr Workaround mit einer Schließung funktioniert gut unter Linux, aber das gleiche Programm stürzt unter Windows ab. – flight