Объекты Python как пользовательские данные в функциях обратного вызова ctypes

StackOverflow https://stackoverflow.com/questions/2469975

Вопрос

Функция С myfunc работает с большим объемом данных.Результаты возвращаются частями в функцию обратного вызова:

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

С использованием cтипы, позвонить не проблема 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 (скажем, список) в качестве пользовательских данных функции обратного вызова?Чтобы сохранить фрагменты результата, я хотел бы сделать, например:

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

userdata=[]

Но я понятия не имею, как преобразовать список Python в c_void_p, чтобы его можно было использовать при вызове myfunc.

Мой текущий обходной путь — реализовать связанный список как структуру ctypes, что довольно громоздко.

Это было полезно?

Решение

Я думаю, вы могли бы использовать API Python C сделать это...возможно, вы могли бы использовать указатель PyObject.

редактировать:Как отметил оператор в комментариях, уже есть py_object тип легко доступен в ctypes, поэтому решение состоит в том, чтобы сначала создать 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)))
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top