Question

La fonction C myfunc fonctionne sur un plus grand bloc de données. Les résultats sont retournés en morceaux à une fonction de rappel:

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

Utilisation ctypes , il n'y a pas de gros problème pour appeler myfunc à partir du code Python, et d'avoir les résultats retournés à une fonction de rappel Python. Ce travail de rappel 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)

Mais, est-il possible de donner un objet Python (par exemple une liste) comme userdata à la fonction de rappel? Pour ranger les morceaux de résultats, je voudrais faire par exemple:.

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

userdata=[]

Mais je ne sais pas comment lancer la liste Python à un c_void_p, de sorte qu'il peut être utilisé dans l'appel à MYFUNC.

Ma solution actuelle est de mettre en œuvre une liste chaînée comme une structure ctypes, ce qui est assez lourd.

Était-ce utile?

La solution

Je suppose que vous pouvez utiliser le Python C API pour le faire ... peut-être vous pouvez utiliser un pointeur PyObject.

modifier : Comme l'op a souligné dans les commentaires, il y a déjà un py_object de type facilement disponible dans ctypes, de sorte que la solution est de créer d'abord un objet ctypes.py_object dans la liste python, puis couler à c_void_p de le transmettre comme argument à la fonction C (je pense que cette étape pourrait être inutile en tant que paramètre typée comme void* doit accepter tout pointeur, et il serait plus rapide de passer juste un byref). Dans le rappel, les étapes inverses sont effectuées (coulée à partir du pointeur de vide à un pointeur vers py_object puis obtenir la valeur du contenu).

Une solution pourrait être d'utiliser une fermeture pour votre fonction de rappel il connaît déjà la liste dans laquelle il doit ajouter les éléments ...

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)))
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top