Python возражает как userdata в ctypes функциях обратного вызова

Функция 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 структуру, которая является довольно громоздкой.

10
задан flight 18 March 2010 в 13:06
поделиться

1 ответ

Думаю, для этого можно использовать 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)))
3
ответ дан 4 December 2019 в 04:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: