Как вернуть массив из С++-функции в Python с использованием ctypes
Я использую ctypes для реализации функции С++ в Python. Функция С++ должна возвращать указатель на массив. К сожалению, я не понял, как получить доступ к массиву в Python. Я попробовал numpy.frombuffer, но это не удалось. Он просто вернул массив произвольных чисел. Очевидно, я не использовал его правильно. Вот простой пример с массивом размером 10:
Содержимое функции .cpp:
extern "C" int* function(){
int* information = new int[10];
for(int k=0;k<10;k++){
information[k] = k;
}
return information;
}
Содержимое 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)
Чтобы скомпилировать файл С++, я использую:
g++ -c -fPIC function.cpp -o function.o
g++ -shared -Wl,-soname,library.so -o library.so function.o
Есть ли у вас какие-либо предложения о том, что мне нужно сделать для доступа к значениям массива в Python?
Ответы
Ответ 1
function.cpp
возвращает массив int, а wrapper.py
пытается интерпретировать их как парные. Измените ArrayType
на ctypes.c_int * 10
, и он должен работать.
Скорее просто использовать np.ctypeslib
вместо frombuffer
самостоятельно. Это должно выглядеть примерно так:
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()
Ответ 2
Ваш код python будет работать после некоторых незначительных изменений:
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]
В основном есть два изменения:
-
удалите связанный с numpy код и вызов ctypes.cast
, так как они нам не нужны.
-
укажите тип возврата в ctypes.POINTER(ctypes.c_int * 10)
.
По умолчанию предполагается, что внешние функции возвращают тип C int, поэтому нам нужно изменить его на нужный тип указателя.
Кстати, возвращение массива new
ed из кода C в код Python кажется неуместным. Кто и когда освободит память? Лучше создавать массивы в коде Python и передавать их на C-код. Таким образом, ясно, что код Python владеет массивами и берет на себя ответственность за создание и восстановление их пространств.