ctypesで定義した構造体の配列を初期化する

PythonからWin32APIを直接叩きたい機会があったのですが、PyWin32に使いたかったRAWINPUT周りの構造体や関数が用意されていなかったため、ctypesから使用することにしました。当然Cの引数や返り値をラップする必要がでてくるわけですが、見かけた構造体の配列の初期化の構文で一瞬むむ??っとなったのでメモです。

ctypesのリファレンスの例を借りると、構造体の配列は

from ctypes import *
class POINT(Structure):
    _fields_ = ("x", c_int), ("y", c_int)
TwoPointsArrayType = POINT * 2
array = TwoPointsArrayType(POINT(1,2),POINT(3,4))

という風に書けるわけですね。ただ、任意の数のPOINT配列を作りたいなぁというときに、わざわざ配列タイプをtypedefするのも面倒なので一行で書きたくなるわけです。 そうするとこうなります。

# 10個のPOINTを含むリスト
p_list = []
for i in range(10):
  p_list.append(POINT(i,i))
# ctypeで使う配列
array = (POINT*len(p_list))(*(p for p in p_list))

一瞬C言語のポインタ表現かと見間違えました笑。リストを*で展開して初期化の引数に渡してあげているんですね。慣れればなんてことないですが、初めて見るとなんだこれとなったのでメモでした!