私はctypesを使用してPythonでC++関数を実装しています。 C++関数は、配列へのポインターを返す必要があります。残念ながら、Pythonで配列にアクセスする方法がわかりません。 numpy.frombufferを試しましたが、成功しませんでした。任意の数の配列を返しただけです。明らかに、私はそれを正しく使用しませんでした。サイズ10の配列を使用した簡単な例を次に示します。
Function.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)
私が使用しているC++ファイルをコンパイルするには:
g++ -c -fPIC function.cpp -o function.o
g++ -shared -Wl,-soname,library.so -o library.so function.o
Pythonで配列値にアクセスするために私がしなければならないことについて何か提案はありますか?
function.cpp
はint配列を返しますが、wrapper.py
はそれらをdoubleとして解釈しようとします。 ArrayType
をctypes.c_int * 10
に変更すると、機能するはずです。
自分でfrombuffer
の代わりに np.ctypeslib
を使用する方がおそらく簡単です。これは次のようになります
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()
あなたの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]
_
基本的に2つの変更があります。
numpy関連のコードと_ctypes.cast
_呼び出しは必要ないので、削除します。
戻り値の型をctypes.POINTER(ctypes.c_int * 10)
に指定します。
デフォルトでは、外部関数はC int型を返すと想定されているため、目的のポインター型に変更する必要があります。
ところで、CコードからPythonコードにnew
ed配列を返すのは不適切なようです。誰がいつメモリを解放しますか?Pythonコードを作成し、Cコードに渡します。このようにして、Python code owns配列であり、スペースの作成と再利用を担当することは明らかです。