首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C结构的Python包装器中的深度复制

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

Stack Overflow用户
提问于 2020-05-12 22:36:31
回答 1查看 545关注 0票数 2

我使用SWIG为C库生成Python绑定。库定义了一个具有值语义的结构。在C++术语中,结构将是POD --用memcpy复制它会产生一个语义正确的副本。

clib.h:

代码语言:javascript
复制
struct s
{
     int i;
};

我使用SWIG将其编译成Python模块。关于构建过程的详细信息在这个问题的“附录”中。

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

代码语言:javascript
复制
#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);
}

在Python包装器中,与预期的一样,我们有引用语义:

代码语言:javascript
复制
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包装器(参考文献)生成一个。我们可以写:

代码语言:javascript
复制
s3 = clib.s(s1)

但是对于C库,不会生成这个包装器:

代码语言:javascript
复制
TypeError: __init__() takes exactly 1 argument (2 given)

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

代码语言:javascript
复制
from copy import deepcopy
s4 = deepcopy(s1)

但事实并非如此:

代码语言:javascript
复制
TypeError: can't pickle SwigPyObject objects

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

要复制的细节

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

代码语言:javascript
复制
%module clib

%{
#include "clib.h"
%}

%include "clib.h"

使用setup.py创建Python模块

代码语言:javascript
复制
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构建整个过程

代码语言:javascript
复制
swig: setup.py clib_wrap.c
    python2 setup.py build_ext --inplace

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

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-17 18:13:41

虽然C库不能有构造函数/析构函数,但您可以在事实之后为SWIG包装器参考文献: swig docs 5.5.6定义它们。请注意,必须仔细编写构造函数:

普通的C++构造函数实现有一个微妙的区别,那就是尽管构造函数声明与普通的C++构造函数一样,新构造的对象必须被返回,就像构造函数声明有返回值一样。

测试。我:

代码语言:javascript
复制
%module test

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

%include "clib.h"

%extend s {       // add additional methods to the s struct
    s(int i) {    // constructor
        struct s* t = malloc(sizeof(struct s));
        t->i = i;
        return t;
    }
    s(struct s* o) { // copy constructor
        struct s* t = malloc(sizeof(struct s));
        t->i = o->i;
        return t;
    }
    ~s() {           // destructor
        free($self);
    }
}

用例:

代码语言:javascript
复制
>>> import test
>>> s1 = test.s(5)
>>> s1.i
5
>>> s2 = test.s(s1)  # copy
>>> s2.i
5
>>> s2.i = 7
>>> s1.i
5
>>> s2.i
7
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61763169

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档