[英]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
接口,例如M2Crypto
, openssl
包裝器遵循該方法。
另一個選擇是使用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.