12

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

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

ctypesを使用するとmyfunc、Pythonコードから呼び出して、結果を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=[]

しかし、Pythonリストをc_void_pにキャストして、myfuncの呼び出しで使用できるようにする方法がわかりません。

私の現在の回避策は、リンクリストをctypes構造として実装することですが、これは非常に面倒です。

4

1 に答える 1

3

PythonCAPIを使用してそれを行うことができると思います...多分PyObjectポインターを使用することができます。

編集:opがコメントで指摘したpy_objectように、ctypesですぐに利用できる型がすでにあるので、解決策は、最初ctypes.py_objectにpythonリストからオブジェクトを作成し、次にそれをキャストしc_void_pてC関数への引数として渡すことです(Iこのステップはvoid*、任意のポインターを受け入れるように入力されたパラメーターとしては不要である可能性があり、 byref)だけを渡す方が高速であると考えてください。コールバックでは、逆の手順が実行されます(voidポインターからへのポインターにキャストしてから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)))
于 2010-03-18T13:16:55.793 に答える