为包含 Swig 对象的 Python 对象创建复制 class 方法
Create a copy class method for a Python object containing a Swig object
我创建了一个 Python class,其属性是一个 Swig 对象(恰好是 C
结构的包装器)。我希望能够创建 class 的副本,例如,通过定义 __copy__
方法,它包含 Swig 对象的独立副本(使用 copy 模块的 copy
class 只是创建了一个指向原始对象的指针,deepcopy
失败了)。
有谁知道您是否可以只复制 Python 中的内存块,并使用它来复制包含 Swig 对象的属性?或者,我可以在创建 Swig 对象的 Swig 接口文件中创建一个 __copy__
或 __deepcopy__
方法,它能够使用 C
s memcpy
吗?
通过查看 __deepcopy__
在 Swig 接口中实现的 LAL, finding the Swig macros for allocating and deallocating memory, and looking at my own(!) example 将 Swig 接口扩展到 C
结构,我想出了如何创建一个 __deepcopy__
Swig 包装结构的方法。
重复我的gist,并扩展它添加一个__deepcopy__
方法如下:
假设您有一些 C
代码包含如下结构:
/* testswig.h file */
#include <stdlib.h>
#include <stdio.h>
typedef struct tagteststruct{
double *data;
size_t len;
} teststruct;
teststruct *CreateStruct(size_t len);
其中结构将包含一个 data
长度为 len
的数组。函数 CreateStruct()
分配
用于结构实例化的内存,定义为
/* 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 类似列表的方法可能会很有用,
例如,从 data
数组中添加或获取项目。为此,您可以创建以下 SWIG 接口文件:
/* 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;
}
在上面的例子中,它在结构中添加了以下方法:
__getitem__
:这允许像 python 中的列表项一样访问结构的 data
数组,例如,使用 x[0]
returns 值在 teststruct->data[0]
__setitem__
:这允许将结构的 data
数组值设置为 python 中的列表项,例如,使用 x[0] = 1.2
设置 teststruct->data[0]
__len__
:这个returns使用len(x)
时data
数组的长度
insert()
:这会将一个值插入到数组中的特定索引中,就像 __getitem__
__deepcopy__
:这允许使用 deepcopy
创建结构的副本。
该示例还展示了如何对这些方法执行一些异常检查,特别是确保请求的索引不超过数组的大小。
要编译和使用此示例,您可以执行以下操作(例如,参见 SWIG 的 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
命令生成。
然后可以在 python 中使用该结构,如下例所示:
>>> 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 包装结构本身可以在 class 中,例如:
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
我创建了一个 Python class,其属性是一个 Swig 对象(恰好是 C
结构的包装器)。我希望能够创建 class 的副本,例如,通过定义 __copy__
方法,它包含 Swig 对象的独立副本(使用 copy 模块的 copy
class 只是创建了一个指向原始对象的指针,deepcopy
失败了)。
有谁知道您是否可以只复制 Python 中的内存块,并使用它来复制包含 Swig 对象的属性?或者,我可以在创建 Swig 对象的 Swig 接口文件中创建一个 __copy__
或 __deepcopy__
方法,它能够使用 C
s memcpy
吗?
通过查看 __deepcopy__
在 Swig 接口中实现的 LAL, finding the Swig macros for allocating and deallocating memory, and looking at my own(!) example 将 Swig 接口扩展到 C
结构,我想出了如何创建一个 __deepcopy__
Swig 包装结构的方法。
重复我的gist,并扩展它添加一个__deepcopy__
方法如下:
假设您有一些 C
代码包含如下结构:
/* testswig.h file */
#include <stdlib.h>
#include <stdio.h>
typedef struct tagteststruct{
double *data;
size_t len;
} teststruct;
teststruct *CreateStruct(size_t len);
其中结构将包含一个 data
长度为 len
的数组。函数 CreateStruct()
分配
用于结构实例化的内存,定义为
/* 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 类似列表的方法可能会很有用,
例如,从 data
数组中添加或获取项目。为此,您可以创建以下 SWIG 接口文件:
/* 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;
}
在上面的例子中,它在结构中添加了以下方法:
__getitem__
:这允许像 python 中的列表项一样访问结构的data
数组,例如,使用x[0]
returns 值在teststruct->data[0]
__setitem__
:这允许将结构的data
数组值设置为 python 中的列表项,例如,使用x[0] = 1.2
设置teststruct->data[0]
__len__
:这个returns使用len(x)
时insert()
:这会将一个值插入到数组中的特定索引中,就像__getitem__
__deepcopy__
:这允许使用deepcopy
创建结构的副本。
data
数组的长度
该示例还展示了如何对这些方法执行一些异常检查,特别是确保请求的索引不超过数组的大小。
要编译和使用此示例,您可以执行以下操作(例如,参见 SWIG 的 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
命令生成。
然后可以在 python 中使用该结构,如下例所示:
>>> 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 包装结构本身可以在 class 中,例如:
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