我正在使用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生成的类)来自动处理对象创建和销毁(以及提供一些OBVIOUS成员函数,如MYSTRUCT_Func1()。
但是,如果我对SWIG生成的类进行包装/子类化,那么我不确定是否可以将新类传递给期望指向C结构的指针的C API函数。我无法直接修改SWIG生成的类(或至少我不应该) - 出于显而易见的原因。
解决此问题的最佳方法是什么?一种更加pythonic的创建/销毁对象的方式,同时能够将指针直接传递给暴露的C函数?
答案 0 :(得分: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
或编写getter和setter来执行此操作。
您还可以将clone
功能纳入此设计中。
编辑:关于你的评论,假设你有一个全局函数,它指向MyStruct
:
int gFunc(MyStruct* ms);
在Python方面,你可以编写一个包装器,如下所示:
def gFuncWrapper(mystruct):
return fb.gFunc(mystruct.ms)
我希望这会有所帮助。
答案 1 :(得分: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)
答案 2 :(得分:0)
您可以命名SWIG生成的模块_foobar
并编写一个纯Python模块foobar
来定义必要的pythonic接口,例如,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。