Cómo devolver un array desde la función C ++ a Python usando ctypes

Estoy usando ctypes para implementar una función de C ++ en Python. La función C ++ debe devolver un puntero a una matriz. Desafortunadamente, no he descubierto cómo acceder a la matriz en Python. Intenté numpy.frombuffer, pero eso no tuvo éxito. Acaba de devolver una serie de números arbitrarios. Obviamente no lo usé correctamente. Aquí hay un ejemplo simple con una matriz de tamaño 10:

Contenido de function.cpp:

extern "C" int* function(){ int* information = new int[10]; for(int k=0;k<10;k++){ information[k] = k; } return information; } 

Contenido de wrapper.py:

 import ctypes import numpy as np output = ctypes.CDLL('./library.so').function() ArrayType = ctypes.c_double*10 array_pointer = ctypes.cast(output, ctypes.POINTER(ArrayType)) print np.frombuffer(array_pointer.contents) 

Para comstackr el archivo C ++ que estoy usando:

 g++ -c -fPIC function.cpp -o function.o g++ -shared -Wl,-soname,library.so -o library.so function.o 

¿Tiene alguna sugerencia sobre qué debo hacer para acceder a los valores de la matriz en Python?

function.cpp devuelve una matriz int, mientras que wrapper.py intenta interpretarlos como dobles. Cambie ArrayType a ctypes.c_int * 10 y debería funcionar.


Probablemente sea más fácil usar np.ctypeslib lugar de hacerlo desde el frombuffer . Esto debería parecer algo como

 import ctypes from numpy.ctypeslib import ndpointer lib = ctypes.CDLL('./library.so') lib.function.restype = ndpointer(dtype=ctypes.c_int, shape=(10,)) res = lib.function() 

Tu código de Python funcionará después de algunas modificaciones menores:

 import ctypes f = ctypes.CDLL('./library.so').function f.restype = ctypes.POINTER(ctypes.c_int * 10) print [i for i in f().contents] # output: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

Básicamente hay dos cambios:

  1. elimine el código relacionado con ctypes.cast y la llamada a ctypes.cast ya que no los necesitamos.

  2. especifique el tipo de retorno a ctypes.POINTER(ctypes.c_int * 10) .

    Por defecto, se asume que las funciones externas devuelven el tipo C int, por lo tanto, necesitamos cambiarlo al tipo de puntero deseado.

Por cierto, devolver una matriz ed new de código C a código Python parece inapropiado. ¿Quién y cuándo liberará la memoria? Es mejor crear matrices en el código Python y pasarlas al código C. De esta manera queda claro que el código Python es el propietario de los arreglos y asume la responsabilidad de crear y reclamar sus espacios.