Objetos Python como Dados UserDatos em Funções de Retorno de Calleiro Ctypes
Pergunta
A função C. myfunc
opera em um pedaço maior de dados. Os resultados são retornados em pedaços para uma função de retorno de chamada:
int myfunc(const char *data, int (*callback)(char *result, void *userdata), void *userdata);
Usando ctypes, não é grande coisa para ligar myfunc
do código Python e para que os resultados sejam retornados a uma função de retorno de chamada Python. Este retorno de chamada funciona bem.
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)
Mas, existe alguma maneira de fornecer um objeto Python (digamos uma lista) como dados do usuário para a função de retorno de chamada? Para armazenar os pedaços de resultado, eu gostaria de fazer, por exemplo:
def mycb(result, userdata):
userdata.append(result)
userdata=[]
Mas não tenho idéia de como lançar a lista Python para um C_Void_P, para que ela possa ser usada na chamada para o MyFunc.
Minha solução alternativa atual é implementar uma lista vinculada como uma estrutura CTYPES, que é bastante pesada.
Solução
Eu acho que você poderia usar o Python C API Para fazer isso ... talvez você possa usar um ponteiro Pyobject.
editar: Como o OP apontou nos comentários, já existe um py_object
digite prontamente disponível em ctypes, então a solução é criar primeiro a ctypes.py_object
objeto da lista de Python e depois lançá -la para c_void_p
passar como um argumento para a função C (acho que essa etapa pode ser desnecessária como um parâmetro digitado como void*
deve aceitar qualquer ponteiro, e seria mais rápido passar apenas um byref
). No retorno de chamada, as etapas reversas são feitas (lançando do ponteiro vazio a um ponteiro para py_object
e depois obter o valor do conteúdo).
Uma solução alternativa pode ser usar um fechamento para sua função de retorno de chamada, para que já saiba em qual lista precisa anexar os itens ...
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)))