Объекты Python как userdata в функциях обратного вызова ctypes - PullRequest
10 голосов
/ 18 марта 2010

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

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

userdata=[]

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

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

1 Ответ

3 голосов
/ 18 марта 2010

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

edit : Как указывалось в комментариях к оператору, в ctypes уже есть тип py_object, поэтому решение состоит в том, чтобы сначала создать объект ctypes.py_object из списка python, а затем приведение к c_void_p для передачи его в качестве аргумента функции C (я думаю, что этот шаг может быть ненужным, так как параметр, типизированный как void*, должен принимать любой указатель, и он будет быстрее передавать только byref) , В обратном вызове выполняются обратные шаги (приведение от пустого указателя к указателю на 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)))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...