我正在使用 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 结构的指针的 C API 函数,我无法直接修改 SWIG 生成的类(或者至少我不能)。不应该)-出于明显的原因,
解决这个问题的最佳方法是什么?一种更Python式的创建/销毁对象的方法,同时能够直接将指针传递给公开的C函数?
I am using SWIG to generate Python language bindings to my C library. I have managed to build the bindings and exported data structures, but I'm having to jump through some hoops when using the library.
For example the C header has data types and function prototypes as follows:
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 */
In my SWIG interface file, I am exporting both the functions and the MyStruct data type. Assuming my python extension module is called foobar, I can then write Python script like this:
#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)
It is very cumbersome (and error prone) to declare an object and then assign a pointer to it before using it. Is there a better way of using the SWIG generated classes?. I was thinking of wrapping higher level classes (or subclassing the SWIG generated classes) to automagically take care of object creation and destruction (as well as providing some OBVIOUS member functions like MYSTRUCT_Func1().
HOWEVER, if I do wrap/subclass the SWIG generated classes, then I am not sure that I can pass the new classes to the C API functions that expect a pointer to a C struct. I can't modify the SWIG generated classes directly (or atleast I shouldn't) - for OBVIOUS reasons.
What is the best way to solve this problem? A more pythonic way of creating/destroying objects, whilst at the same time being able to pass pointers directly to the exposed C functions?
发布评论
评论(3)
您的代码:
仅将类分配给
ms
,而不是类的实例,这就是注释行失败的原因。以下应该有效:Your code:
Only assigns the class to
ms
, not an instance of a class, which is why the commented line fails. The following should work:在 Python 端编写一个包装器对我来说似乎是个好主意,不知道为什么你认为这行不通。
如果您需要访问结构体的成员,则可以使用 self.ms.member 或编写 getter 和 setter 来实现。
您还可以将您的
clone
功能融入到此设计中。编辑:关于你的评论,假设你有一个全局函数,它接受一个指向
MyStruct
的指针:在Python端,你可以编写一个包装器,如下所示:
我希望这个有帮助。
Writing a wrapper on the Python side seems like a good idea to me, not sure why you think that is not going to work.
And if you need to access the members of the struct, then you can do so with
self.ms.member
or by writing getters and setters.You can also fit your
clone
function into this design.Edit: Regarding your comment, let's say you have a global function that takes a pointer to
MyStruct
:In the Python side, you can write a wrapper as follows:
I hope this helps.
您可以将 SWIG 生成的模块命名为
_foobar
并编写一个纯 Python 模块foobar
来定义必要的 pythonic 接口,例如M2Crypto
一个openssl
包装器遵循这种方法。另一种选择是使用 Cython 直接在 C 中创建接口:
这将创建可从 Python 中使用的 Python C 扩展类型
MyStruct
:请参阅 包装 Person.h 以获得完整示例。
You could name your SWIG-generated module
_foobar
and write a pure Python modulefoobar
that defines the necessary pythonic interface e.g.,M2Crypto
anopenssl
wrapper follows that approach.Another option is to use Cython to create the interface straight in C:
This creates Python C extension type
MyStruct
that can be used from Python as:See wrap Person.h for a complete example.