Функция C myfunc
воздействует на больший блок данных. Результаты возвращаются в блоках к функции обратного вызова:
int myfunc(const char *data, int (*callback)(char *result, void *userdata), void *userdata);
Используя ctypes, это не грандиозное предприятие звонить myfunc
из кода Python, и иметь результаты, возвращаемые к функции обратного вызова Python. Этот обратный вызов хорошо работает.
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)
Но, есть ли какой-либо способ дать объект Python (скажите что список) как userdata к функции обратного вызова? Чтобы хранить блоки результата, я хотел бы сделать, например:
def mycb(result, userdata):
userdata.append(result)
userdata=[]
Но я понятия не имею, как бросить список Python к c_void_p, так, чтобы он мог привыкнуть в вызове к myfunc.
Мое текущее обходное решение должно реализовать связанный список как ctypes структуру, которая является довольно громоздкой.
Думаю, для этого можно использовать Python C API... возможно, вы можете использовать указатель PyObject.
edit: Как отметил в комментариях автор, в ctypes уже есть тип py_object
, легко доступный, поэтому решение состоит в том, чтобы сначала создать ctypes. py_object
объект из списка python, а затем привести его к c_void_p
, чтобы передать его в качестве аргумента в функцию C (я думаю, что этот шаг может быть излишним, поскольку параметр, типизированный как void*
, должен принимать любой указатель, и было бы быстрее передать просто byref
). В обратном вызове выполняются обратные действия (приведение от указателя на void к указателю на py_object
, а затем получение значения содержимого).
Обходным решением может быть использование закрытия для вашей функции обратного вызова, чтобы она уже знала, в какой список ей нужно добавить элементы...
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)))