为包含Swig对象的Python对象创建复制类方法 [英] Create a copy class method for a Python object containing a Swig object
问题描述
我创建了一个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 C
s memcpy
?
推荐答案
通过查看在Swig界面中为 C
结构的示例,我已经弄清楚了如何创建__deepcopy __
方法用于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)
时 -
insert()
:这会将值插入到数组中的特定索引中,就像__ getitem __
-
__ deepcopy __
:这允许使用deepcopy
创建该结构的副本.
data
数组的长度.__getitem__
: this allows the structure'sdata
array to be accessed like a list item in python, e.g., usingx[0]
returns the value inteststruct->data[0]
__setitem__
: this allows the structure'sdata
array values to be set like a list item in python, e.g., usingx[0] = 1.2
sets the value inteststruct->data[0]
__len__
: this returns the length of thedata
array when usinglen(x)
insert()
: this inserts a value into a particular index in the array like with__getitem__
__deepcopy__
: this allows the use ofdeepcopy
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屋!