C结构的Python SWIG包装中的深度复制

我正在使用SWIG为C库生成Python绑定。库使用值语义定义结构。在C++术语中,结构将是POD -复制它,使用 MycPy 生成一个语义正确的拷贝。

clib.h:

结构
{
int i;
};

我使用SWIG将其编译成一个Python模块。有关构建过程的详细信息,请参见本问题的“附录”

对于C类型的赋值运算符,我们可以验证C类型的赋值运算符的语义:

#包括<断言h>
#包括“clib.h”
int main()
{
结构s1;
s1.i=100;
结构s2=s1;
断言(s2.i==100);
s2.i=101;
断言(s1.i==100);
}

正如预期的那样,在Python包装中,我们使用了引用语义:

导入clib
s1=clib.s()
s1.i=100
s2=s1
断言s2.i==100
s2.i=101
断言s1.i==101

如果我们的库是用C++编写的,而S/有一个拷贝构造函数,SWIG也会为Python包装器生成一个(引用)。我们可以写:

s3=clib.s(s1)

但对于C库,不会生成此包装:

TypeError:\uuuuu init\uuuuu()正好接受1个参数(给定2个)

我们可能希望SWIG为copy.deepcopy生成适当的魔术方法:

从复制导入deepcopy
s4=深度复制(s1)

但它没有:

类型错误:无法pickle SwigPyObject对象

我很困惑。这看起来应该很简单,但我什么也找不到。在“SWIG和Python”文档中,“复制”一词只出现在C++复制构造器的先前链接的注释中,以及在生成的包装代码的一些低层次细节中。关于堆栈溢出的最接近的问题有一个极其复杂的答案


复制的细节

定义一个简单的SWIG接口文件clib.i

%module clib
%{
#包括“clib.h”
%}
%包括“clib.h”

使用setup.py创建Python模块:

distutils.core导入设置中的

,扩展
clib=扩展(
“_clib”,
sources=[“clib_wrap.c”],
额外编译参数=[“-g”],
)
设置(name=“clib”,version=“1.0”,ext\u模块=[clib])

使用Makefile构建整个过程:

swig:setup.py clib\u wrap.c
python2 setup.py build\u ext–就地
clib_wrap.c:clib.i
swig-pythonclib.i

然后,完全按照上面列出的方法编译/运行Python和C测试程序

虽然C库不能有构造函数/析构函数,但您可以在SWIG包装器ref:SWIG docs 5.5.6之后定义它们。注意,施工人员必须仔细书写:

虽然与普通C++ C++构造函数有一个细微的差别,但是尽管构造函数声明与普通C++构造函数相同,但是新构造的对象必须返回,就像构造函数声明有返回值一样。

测试一:

%模块测试
%{
#包括<stdlib.h>
#包括“clib.h”;
%}
%包括「;clib.h";
%扩展s{//向s结构添加其他方法
s(inti){//constructor
struct s*t=malloc(sizeof(struct s));
t->i=i;
返回t;
}
s(结构s*o){//复制构造函数
struct s*t=malloc(sizeof(struct s));
t->i=o->i;
返回t;
}
~s(){//析构函数
免费($self);
}
}

用例:

&gt&燃气轮机&燃气轮机;导入测试
&燃气轮机&燃气轮机&燃气轮机;s1=试验s(5)
&燃气轮机&燃气轮机&燃气轮机;s1.i
5.
&燃气轮机&燃气轮机&燃气轮机;s2=测试s(s1)#副本
&燃气轮机&燃气轮机&燃气轮机;s2.i
5.
&燃气轮机&燃气轮机&燃气轮机;s2.i=7
&燃气轮机&燃气轮机&燃气轮机;s1.i
5.
&燃气轮机&燃气轮机&燃气轮机;s2.i
7.

发表评论