为包含Swig对象的Python对象创建复制类方法 [英] Create a copy class method for a Python object containing a Swig object

查看:71
本文介绍了为包含Swig对象的Python对象创建复制类方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个Python类,其属性为Swig对象(恰好是 C 结构的包装).我希望能够创建该类的副本,例如通过定义 __ copy __ 方法,其中包含Swig对象的独立副本(使用

I have created a Python class with an attribute that is a Swig object (which happens to be a wrapper of a C structure). I want to be able to create copies of that class, e.g., by defining a __copy__ method, that contain independent copies of the Swig object (using the copy modules' copy class just creates a pointer to the original object, and deepcopy fails).

有人知道您是否只能在Python中复制内存块,并使用它来复制包含Swig对象的属性吗?或者,是否可以在创建Swig对象的Swig接口文件中创建 __ copy __ __ deepcopy __ 方法,该对象可以使用 C s memcpy ?

Does anyone know if you can just copy chunks of memory in Python, and use this to copy the attribute containing the Swig object? Or, could I create a __copy__ or __deepcopy__ method in the Swig interface file that created the Swig object, which is able to use Cs memcpy?

推荐答案

通过查看在Swig界面中为__deepcopy __ lscsoft/lalsuite/blob/ff83af3997ef27b65fcc74d740421750aa3e35b2/lal/swig/SWIGPython.i#L202"rel =" nofollow noreferrer> LAL ,找到Swig

From looking at the __deepcopy__ implemented in the Swig interface for LAL, finding the Swig macros for allocating and deallocating memory, and looking at my own(!) example of extending the Swig interface to a C structure, I have figured out how to create a __deepcopy__ method for the Swig-wrapped structure.

重复我的要点,并将其扩展以添加 __ deepcopy __ 方法如下:

Repeating my gist, and extending it to add a __deepcopy__ method is as follows:

假设您有一些包含如下结构的 C 代码:

Say you have some C code containing a structure like this:

/* testswig.h file */
#include <stdlib.h>
#include <stdio.h>

typedef struct tagteststruct{
  double *data;
  size_t len;
} teststruct;

teststruct *CreateStruct(size_t len);

其中结构将包含长度为 len data 数组.函数 CreateStruct()分配用于实例化结构的内存,并定义为

where the structure will contain a data array of length len. The function CreateStruct() allocates memory for an instantiation of the structure, and is defined as

/* testswig.c file */
#include "testswig.h"

/* function for allocating memory for test struct */
teststruct *CreateStruct(size_t len){
  teststruct *ts = NULL;

  ts = (teststruct *)malloc(sizeof(teststruct));
  ts->data = (double *)malloc(sizeof(double)*len);
  ts->len = len;
  return ts;
}

如果将其与SWIG一起包装以便在python中使用,那么使用一些类似于python list的方法可能会很有用,例如,从 data 数组添加或获取项目.为此,您可以创建以下SWIG接口文件:

If you wrap this with SWIG for use in python, then it might be useful to have some python list-like methods available to, e.g., add or get items from the data array. To do this you can create the following SWIG interface file:

/* testswig.i */

%module testswig

%include "exception.i"

%{
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "testswig.h"
static int teststructErr = 0; // flag to save test struct error state
%}

%include "testswig.h"

// set exception handling for __getitem__
%exception tagteststruct::__getitem__ {
  assert(!teststructErr);
  $action
  if ( teststructErr ){
    teststructErr = 0; // clear flag for next time
    SWIG_exception(SWIG_IndexError, "Index out of bounds");
  }
}

// set exception handling for __setitem__
%exception tagteststruct::__setitem__ {
  assert(!teststructErr);
  $action
  if ( teststructErr ){
    teststructErr = 0; // clear flag for next time
    SWIG_exception(SWIG_IndexError, "Index out of bounds");
  }
}

// set exception handling for insert()
%exception tagteststruct::insert {
  assert(!teststructErr);
  $action
  if ( teststructErr ){
    teststructErr = 0; // clear flag for next time
    SWIG_exception(SWIG_IndexError, "Index out of bounds");
  }
}

// "extend" the structure with various methods
%extend tagteststruct{
  // add a __getitem__ method to the structure to get values from the data array
  double __getitem__(size_t i) {
    if (i >= $self->len) {
      teststructErr = 1;
      return 0;
    }
    return $self->data[i];
  }

  // add a __setitem__ method to the structure to set values in the data array
  void __setitem__(size_t i, double value) {
    if ( i >= $self->len ){
      teststructErr = 1;
      return;
    }
    $self->data[i] = value;  
  }


  size_t __len__(){
    return $self->len;
  }

  void insert(size_t i, double value) {
    if ( i >= $self->len ){
      teststructErr = 1;
      return;
    }
    $self->data[i] = value;
  }

  %typemap(in, noblock=1) const void *memo "";
  struct tagteststruct * __deepcopy__(const void *memo) {
    // copy structure
    struct tagteststruct * scopy = %new_copy(*$self, struct tagteststruct);
    // copy array within the structure
    scopy->data = %new_copy_array($self->data, $self->len, double);
    return scopy;
  }
  %clear const void *memo;
}

在上面的示例中,它向结构添加了以下方法:

In the above example, it adds the following methods to the structure:

  • __ getitem __ :这允许像在python中的列表项一样访问结构的 data 数组,例如,使用 x [0] 返回 teststruct-> data [0]
  • 中的值
  • __ setitem __ :这允许像在python中的列表项一样设置结构的 data 数组值,例如,使用 x [0] = 1.2 设置 teststruct-> data [0]
  • 中的值
  • __ len __ :这会返回使用 len(x)
  • data 数组的长度.
  • insert():这会将值插入到数组中的特定索引中,就像 __ getitem __
  • __ deepcopy __ :这允许使用 deepcopy 创建该结构的副本.
  • __getitem__: this allows the structure's data array to be accessed like a list item in python, e.g., using x[0] returns the value in teststruct->data[0]
  • __setitem__: this allows the structure's data array values to be set like a list item in python, e.g., using x[0] = 1.2 sets the value in teststruct->data[0]
  • __len__: this returns the length of the data array when using len(x)
  • insert(): this inserts a value into a particular index in the array like with __getitem__
  • __deepcopy__: this allows the use of deepcopy to create a copy of the structure.

该示例还显示了如何对这些方法执行一些异常检查,尤其是确保所请求的索引不超过数组的大小.

The example also shows how to perform some exception checking for these methods, in particular, making sure the requested index does not exceed the size of the array.

要编译并使用此示例,您可以执行以下操作(请参见SWIG的教程):

To compile and use this example, you could do the following (see, e.g., SWIG's tutorial):

$ swig -python testswig.i
$ gcc -c testswig.c testswig_wrap.c -fPIC -I/usr/include/python2.7
$ ld -shared testswig.o testswig_wrap.o -o _testswig.so

在这种情况下, -I/usr/include/python2.7 标志指向包含 Python.h 文件的路径.这 testswig_wrap.c 文件由 swig 命令生成.

where, in this case, the -I/usr/include/python2.7 flag points to the path containing the Python.h file. The testswig_wrap.c file is generated by the swig command.

然后可以在python中使用该结构,如以下示例所示:

The structure can then be used in python as in the following example:

>>> from testswig import CreateStruct
>>> # create an instance of the structure with 10 elements
>>> x = CreateStruct(10)
>>> # set the 5th element of the data array to 1.3
>>> x[4] = 1.3
>>> # output the 5th element of the array
>>> print(x[4])
1.3
>>> # output the length of the array
>>> print(len(x))
10
>>> # create a copy
>>> import copy
>>> y = copy.deepcopy(x)
>>> print(len(y))
10
>>> print(y[4])
1.3
>>> y[4] = 3.4
>>> print(y[4])
3.4
>>> print(x[4])  # check x hasn't been altered
1.3

用Swig包装的结构本身可以在一个类中,例如:

The Swig-wrapped structure could itself be in a class, e.g.,:

from testswig import CreateStruct

class mystruct():
    def __init__(self, size):
        self.array = CreateStruct(size)
        self.name = 'array'

    def __len__(self):
        return len(self.array)

    def __getitem__(self, idx):
        return self.array[idx]

    def __setitem__(self, idx, val):
        self.array[idx] = val

我们可以测试的

>>> x = mystruct(10)
>>> x[4] = 1.2
>>> print(x[4])
1.2
>>> import copy
>>> y = copy.deepcopy(x)
>>> print(y[4])
1.2
>>> y[4] = 3.4
>>> print(y[4])
3.4
>>> print(x[4])  # check it hasn't changed
1.2

这篇关于为包含Swig对象的Python对象创建复制类方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆