[Python] CとのFFI用の構造体の配列
2 min
274 words
Suzuki Shun
PythonからCの関数を呼び出すとき, Cの関数の引数に構造体の配列を渡すことがある.
構造体はctypes.Structureを継承したクラスを作ればいいというのはよく知られているが, その配列をどうやって作るかがあんまり調べても出てこなかったのでメモ.
結論から言うと, 普通にnumpyの配列を使えば良い.
ただし, フィールドへのアクセスを文字列で行う必要がある.
import ctypes
import numpy as np
class Point(ctypes.Structure):
_fields_ = [("x", ctypes.c_double), ("y", ctypes.c_double)]
size = 2
points = np.zeros(size, dtype=Point)
for i in range(size):
points[i]["x"] = 2 * i
points[i]["y"] = 2 * i + 1
print(points)
# [(0., 1.) (2., 3.)]
これで作った配列は以下のようにポインタに変換できる.
これは, Cで言うところのPoint* ptrに相当する.
ptr = points.ctypes.data_as(ctypes.POINTER(Point))
補足
上記のpointsの各要素の型はnumpy.voidとなっている.
そのため, Pointの要素から直接は構成できない.
例えば, 以下のコードはValueError: could not convert string to floatというエラーを吐く.
(このエラーだいぶ分かりづらいな...)
points = np.fromiter(map(lambda i: Point(2 * i, 2 * i + 1), range(size)), dtype=Point)
こういう場合は, numpy.voidに明示的に変換する必要がある.
points = np.fromiter(
map(lambda i: np.void(Point(2 * i, 2 * i + 1)), range(size)), dtype=Point
)
Table of contents