質問

C関数myfuncは、データのより大きなチャンクで動作します。結果はコールバック関数にチャンクで返されます:

int myfunc(const char *data, int (*callback)(char *result, void *userdata), void *userdata);

のctypesのを使用して、Pythonコードからmyfuncを呼び出すと、結果はPythonのコールバック関数に返されて持って大したません。このコールバックは正常に動作します。

myfunc = mylib.myfunc
myfunc.restype = c_int
myfuncFUNCTYPE = CFUNCTYPE(STRING, c_void_p)
myfunc.argtypes = [POINTER(c_char), callbackFUNCTYPE, c_void_p]

def mycb(result, userdata):
    print result
    return True

input="A large chunk of data."
myfunc(input, myfuncFUNCTYPE(mycb), 0)

しかし、コールバック関数へのユーザデータとしてPythonオブジェクト(例えばリスト)を与える方法はありますか?結果チャンクを離れて格納するためには、私は、例えばをしたいと思います:ます。

def mycb(result, userdata):
    userdata.append(result)

userdata=[]

しかし、それはmyfunc関数の呼び出しで使用できるように、私は、c_void_pにPythonのリストをキャストする方法は考えている。

私の現在の回避策は、かなり面倒ですctypesの構造としてリンクリストを実装することです。

役に立ちましたか?

解決

私は多分...あなたはそれを行うためにのPythonのC API を使うことができると思いますあなたはPyObjectポインタを使用することができます。

編集:opがコメントで指摘したように、そこのctypesで容易に入手可能py_objectタイプはすでにですので、解決策は、Pythonのリストから最初のctypes.py_objectオブジェクトを作成し、その後にそれをキャストすることですC関数の引数として渡しするc_void_pは(私は、このステップは任意のポインタを受け入れるべきvoid*として入力パラメータとして不要かもしれないと思うと、それだけでbyrefを渡すために速くなります)。コールバックでは、逆の手順が行われる(py_objectへのポインタを無効ポインタからキャストした後、内容の値を取得する)。

この問題を回避するには...それはすでにそれがアイテムを追加するために持っているリストに知っているように、コールバック関数にクロージャを使用することができます。

myfunc = mylib.myfunc
myfunc.restype = c_int
myfuncFUNCTYPE = CFUNCTYPE(STRING)
myfunc.argtypes = [POINTER(c_char), callbackFUNCTYPE]


def mycb(result, userdata):
    userdata.append(result)

input="A large chunk of data."
userdata = []
myfunc(input, myfuncFUNCTYPE(lambda x: mycb(x, userdata)))
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top