Cómo devolver un array desde la función C++ a Python usando ctypes
arrays return (2)
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 compilar 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 matriz en Python?
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:
elimine el código relacionado con
ctypes.cast
y la llamada actypes.cast
ya que no los necesitamos.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 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.
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.
Es probable que sea más fácil usar np.ctypeslib
lugar de hacerlo desde 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()