2

SWIGを使用して、CライブラリへのPython言語バインディングを生成しています。バインディングを構築し、データ構造をエクスポートすることができましたが、ライブラリを使用するときにいくつかのフープを飛び越える必要があります。

たとえば、Cヘッダーには次のようなデータ型と関数プロトタイプがあります。

struct MyStruct
{
    /* fields */
} 

struct MyStruct * MYSTRUCT_Alloc(void);
void MYSTRUCT_Free(struct MyStruct *);
struct MyStruct  * MYSTRUCT_Clone(const struct MyStruct *);
int MYSTRUCT_Func1(const struct MyStruct *, const int);

/* and so on */

SWIGインターフェイスファイルで、関数とMyStructデータ型の両方をエクスポートしています。私のPython拡張モジュールがfoobarと呼ばれていると仮定すると、次のようなPythonスクリプトを記述できます。

#import foobar as fb

# The line below creates a Python class which is a wrapper to MyStruct. HOWEVER I cannot pass this class to a function like MYSTRUCT_Func1 until I have initialized it by calling MYSTRUCT_Alloc ...

ms = fb.MyStruct  

# This will fail (throws a Python exception)
# ret =  fb.MYSTRUCT_Func1(ms, 123)

# However this works
ms = fb.MYSTRUCT_Alloc()
ret =  fb.MYSTRUCT_Func1(ms, 123)

オブジェクトを宣言し、それを使用する前にオブジェクトへのポインタを割り当てるのは非常に面倒です(そしてエラーが発生しやすくなります)。SWIGで生成されたクラスを使用するより良い方法はありますか?オブジェクトの作成と破棄を自動的に処理するために(またはMYSTRUCT_Func1()のようないくつかのOBVIOUSメンバー関数を提供するために、より高いレベルのクラスをラップする(またはSWIGで生成されたクラスをサブクラス化する)ことを考えていました。

ただし、SWIGで生成されたクラスをラップ/サブクラス化すると、C構造体へのポインターを期待するCAPI関数に新しいクラスを渡すことができるかどうかわかりません。SWIGで生成されたクラスを直接変更することはできません(または少なくとも変更すべきではありません)-明らかな理由から。

この問題を解決するための最良の方法は何ですか?オブジェクトを作成/破棄すると同時に、公開されたC関数に直接ポインターを渡すことができる、よりPython的な方法ですか?

4

3 に答える 3

2

Python側でラッパーを作成することは私には良い考えのように思えますが、なぜそれが機能しないと思うのかわかりません。

class MyStructWrapper:
    def __init__(self):
        self.ms = fb.MYSTRUCT_Alloc()

    def __del__(self):
        fb.MYSTRUCT_Free(self.ms)

    def func1(self, arg):
        return fb.MYSTRUCT_Func1(self.ms, arg)

また、構造体のメンバーにアクセスする必要がある場合は、self.ms.memberゲッターとセッターを使用して、または作成することでアクセスできます。

cloneこのデザインに機能を適合させることもできます。

編集:あなたのコメントに関して、あなたがへのポインタを取るグローバル関数を持っているとしましょうMyStruct

int gFunc(MyStruct* ms);

Python側では、次のようにラッパーを記述できます。

def gFuncWrapper(mystruct):
    return fb.gFunc(mystruct.ms)

これがお役に立てば幸いです。

于 2011-11-08T02:20:59.587 に答える
2

あなたのコード:

ms = fb.MyStruct

# This will fail (throws a Python exception) 
# ret =  fb.MYSTRUCT_Func1(ms, 123) 

msクラスのインスタンスではなく、にクラスを割り当てるだけです。そのため、コメント行は失敗します。以下が機能するはずです。

ms = fb.MyStruct()
ret =  fb.MYSTRUCT_Func1(ms, 123) 
于 2011-11-08T09:20:45.843 に答える
0

SWIGで生成されたモジュールに名前を付けて、必要なpythonicインターフェイスを定義_foobarする純粋なPythonモジュールを作成できます。たとえば、ラッパーはそのアプローチに従います。foobarM2Cryptoopenssl

もう1つのオプションは、Cythonを使用してCで直接インターフェースを作成することです。

cdef class MyStruct:
    cdef MyStruct_ptr this

    def __cinit__(self):
        self.this = MYSTRUCT_Alloc();
        if self.this is NULL:
           raise MemoryError

    def __dealloc__(self):
        if self.this is not NULL:
            MYSTRUCT_Free(self.this)

    def func1(self, n):
        return MYSTRUCT_Func1(self.this, n)

MyStructこれにより、Pythonから次のように使用できるPythonC拡張タイプが作成されます。

ms = Mystruct()
print(ms.func1(123))

完全な例については、wrapPerson.hを参照してください。

于 2011-11-08T02:29:28.413 に答える