簡體   English   中英

SWIG將C庫與Python接口(SWIG生成的類使用起來很麻煩)

[英]SWIG interfacing C library to Python (SWIG generated classes are cumbersome to use)

我正在使用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生成的類? 我正在考慮包裝更高級別的類(或將SWIG生成的類子類化)以自動處理對象的創建和銷毀(以及提供一些顯而易見的成員函數,如MYSTRUCT_Func1())。

但是,如果確實對SWIG生成的類進行包裝/子類化,那么我不確定是否可以將新類傳遞給C API函數,而C API函數需要一個指向C結構的指針。 出於明顯的原因,我不能直接修改SWIG生成的類(或至少不應該修改)。

解決此問題的最佳方法是什么? 創建/銷毀對象的更Python方式,同時又能夠直接將指針傳遞給公開的C函數?

對我而言,在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或編寫getter和setter來進行訪問。

您也可以將clone功能適合此設計。

編輯 :關於您的評論,假設您有一個全局函數,該函數需要一個指向MyStruct的指針:

int gFunc(MyStruct* ms);

在Python方面,您可以編寫包裝器,如下所示:

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

我希望這有幫助。

您的代碼:

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) 

您可以將SWIG生成的模塊_foobar然后編寫一個純Python模塊foobar ,該模塊定義了必要的M2Crypto接口,例如M2Cryptoopenssl包裝器遵循該方法。

另一個選擇是使用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)

這將創建Python C擴展類型MyStruct ,可以在Python中將其用作:

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

有關完整的示例,請參見wrap Person.h

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM