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

C结构的Python SWIG包装中的深度复制,python,c,swig,Python,C,Swig,我正在使用SWIG为C库生成Python绑定。库使用值语义定义结构。在C++术语中,结构将是POD -复制它,使用 MycPy < /Cord>生成一个语义正确的拷贝。 clib.h: struct s { int i; }; 我使用SWIG将其编译成一个Python模块。有关构建过程的详细信息,请参见本问题的“附录” 在C代码中,我们可以验证struct类型变量的赋值运算符是否具有值语义: #include <assert.h> #include "clib.h" i

我正在使用SWIG为C库生成Python绑定。库使用值语义定义结构。在C++术语中,结构将是POD -复制它,使用<代码> MycPy < /Cord>生成一个语义正确的拷贝。 clib.h:

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

在C代码中,我们可以验证struct类型变量的赋值运算符是否具有值语义:

#include <assert.h>
#include "clib.h"

int main()
{
    struct s s1;
    s1.i = 100;

    struct s s2 = s1;
    assert(s2.i == 100);

    s2.i = 101;
    assert(s1.i == 100);
}
import clib

s1 = clib.s()
s1.i = 100

s2 = s1
assert s2.i == 100

s2.i = 101
assert s1.i == 101

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

s3 = clib.s(s1)
但对于C库,不会生成此包装:

TypeError: __init__() takes exactly 1 argument (2 given)
我们可能希望SWIG为
copy.deepcopy
生成适当的魔术方法:

from copy import deepcopy
s4 = deepcopy(s1)
from distutils.core import setup, Extension

clib = Extension(
    "_clib",
    sources=["clib_wrap.c"],
    extra_compile_args=["-g"],
)

setup(name="clib", version="1.0", ext_modules=[clib])
但它没有:

TypeError: can't pickle SwigPyObject objects
我很困惑。这看起来应该很简单,但我什么也找不到。其中,“复制”一词只出现在C++复制构造器的先前链接的注释中,以及在生成的包装代码的一些低层次细节中。这个问题的答案极其复杂


复制的细节 定义一个简单的SWIG接口文件
clib.i

%module clib

%{
#include "clib.h"
%}

%include "clib.h"
使用
setup.py
创建Python模块:

from copy import deepcopy
s4 = deepcopy(s1)
from distutils.core import setup, Extension

clib = Extension(
    "_clib",
    sources=["clib_wrap.c"],
    extra_compile_args=["-g"],
)

setup(name="clib", version="1.0", ext_modules=[clib])
使用
Makefile
构建整个过程:

swig: setup.py clib_wrap.c
    python2 setup.py build_ext --inplace

clib_wrap.c: clib.i
    swig -python clib.i

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

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

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

%module test

%{
#include <stdlib.h>
#include "clib.h"
%}

%include "clib.h"

%extend s {
    s(int i) {
        struct s* t = malloc(sizeof(struct s));
        t->i = i;
        return t;
    }
    s(struct s* o) {
        struct s* t = malloc(sizeof(struct s));
        t->i = o->i;
        return t;
    }
    ~s() {
        free($self);
    }
}

接下来的问题@mark tolonen-文档中没有明确说明:如果我像这样添加我自己的构造函数,我是否也必须添加析构函数,即使它与您的示例中一样微不足道?@Japreis是的,在这种情况下它并不微不足道。你会有内存泄漏。