SWIG/python 数组内部结构

发布于 2024-12-15 04:08:48 字数 501 浏览 0 评论 0原文

我在 header.h 中定义了一个结构,如下所示:

typedef struct {
....
    int      icntl[40];
    double   cntl[15];
    int      *irn, *jcn;
....

当我使用此结构初始化一个对象时,我可以访问整数/双精度数,但不能访问数组。

>> st.icntl
<Swig Object of type 'int *' at 0x103ce37e0>
>> st.icntl[0]
Traceback (most recent call last):
  File "test_mumps.py", line 19, in <module>
    print s.icntl[0]
TypeError: 'SwigPyObject' object is not subscriptable

如何访问读/写中的值?

I've got a structure defined inside header.h that looks like :

typedef struct {
....
    int      icntl[40];
    double   cntl[15];
    int      *irn, *jcn;
....

When I init an object with this structure, I have access to integers/doubles but not arrays.

>> st.icntl
<Swig Object of type 'int *' at 0x103ce37e0>
>> st.icntl[0]
Traceback (most recent call last):
  File "test_mumps.py", line 19, in <module>
    print s.icntl[0]
TypeError: 'SwigPyObject' object is not subscriptable

How to have access to the values in read/write?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

十秒萌定你 2024-12-22 04:08:48

最简单的方法是将数组包装在 struct 中,然后它可以提供 满足“可订阅”要求的额外方法

我整理了一个小例子。它假设您使用的是 C++,但由此构建等效的 C 版本相当简单,只需要一些重复。

首先,C++ 标头包含我们想要包装的 struct 和用于包装固定大小数组的模板:

template <typename Type, size_t N>
struct wrapped_array {
  Type data[N];
};

typedef struct {
    wrapped_array<int, 40> icntl;
    wrapped_array<double, 15> cntl;
    int      *irn, *jcn;
} Test;

我们相应的 SWIG 接口看起来像这样

%module test

%{
#include "test.h"
#include <exception>
%}

%include "test.h"
%include "std_except.i"

%extend wrapped_array {
  inline size_t __len__() const { return N; }

  inline const Type& __getitem__(size_t i) const throw(std::out_of_range) {
    if (i >= N || i < 0)
      throw std::out_of_range("out of bounds access");
    return self->data[i];
  }

  inline void __setitem__(size_t i, const Type& v) throw(std::out_of_range) {
    if (i >= N || i < 0)
      throw std::out_of_range("out of bounds access");
    self->data[i] = v;
  }
}

%template (intArray40) wrapped_array<int, 40>;
%template (doubleArray15) wrapped_array<double, 15>;

:使用 %extend 提供 __getitem__这是Python用于下标读取的方法,__setitem__< /a> 用于写入。 (我们还可以提供一个 __iter__ 来使类型可迭代)。我们还给出了我们想要使用唯一名称的特定 wrapped_array ,以使 SWIG 将它们包装在输出中。

使用提供的接口,我们现在可以执行以下操作:

>>> import test
>>> foo = test.Test()
>>> foo.icntl[30] = -654321
>>> print foo.icntl[30]
-654321
>>> print foo.icntl[40]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "test.py", line 108, in __getitem__
    def __getitem__(self, *args): return _test.intArray40___getitem__(self, *args)
IndexError: out of bounds access

您可能还会发现这种方法 作为替代方案有用/有趣。

The easiest way to do this is to wrap your arrays inside a struct, which can then provide extra methods to meet the "subscriptable" requirements.

I've put together a small example. It assumes you're using C++, but the equivalent C version is fairly trivial to construct from this, it just requires a bit of repetition.

First up, the C++ header that has the struct we want to wrap and a template that we use for wrapping fixed size arrays:

template <typename Type, size_t N>
struct wrapped_array {
  Type data[N];
};

typedef struct {
    wrapped_array<int, 40> icntl;
    wrapped_array<double, 15> cntl;
    int      *irn, *jcn;
} Test;

Our corresponding SWIG interface then looks something like:

%module test

%{
#include "test.h"
#include <exception>
%}

%include "test.h"
%include "std_except.i"

%extend wrapped_array {
  inline size_t __len__() const { return N; }

  inline const Type& __getitem__(size_t i) const throw(std::out_of_range) {
    if (i >= N || i < 0)
      throw std::out_of_range("out of bounds access");
    return self->data[i];
  }

  inline void __setitem__(size_t i, const Type& v) throw(std::out_of_range) {
    if (i >= N || i < 0)
      throw std::out_of_range("out of bounds access");
    self->data[i] = v;
  }
}

%template (intArray40) wrapped_array<int, 40>;
%template (doubleArray15) wrapped_array<double, 15>;

The trick there is that we've used %extend to supply __getitem__ which is what Python uses for subscript reads and __setitem__ for the writes. (We could also have supplied a __iter__ to make the type iteratable). We also gave the specific wraped_arrays we want to use unique names to make SWIG wrap them in the output.

With the supplied interface we can now do:

>>> import test
>>> foo = test.Test()
>>> foo.icntl[30] = -654321
>>> print foo.icntl[30]
-654321
>>> print foo.icntl[40]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "test.py", line 108, in __getitem__
    def __getitem__(self, *args): return _test.intArray40___getitem__(self, *args)
IndexError: out of bounds access

You might also find this approach useful/interesting as an alternative.

计㈡愣 2024-12-22 04:08:48

我会用 python 来做这个

ptr = int(st.icntl)
import ctypes
icntl = ctypes.c_int * 40
icntl = icntl.from_address(ptr)

print icntl[0]
icntl[0] = 1
for i in icntl:
    print i 

I would have done this in python

ptr = int(st.icntl)
import ctypes
icntl = ctypes.c_int * 40
icntl = icntl.from_address(ptr)

print icntl[0]
icntl[0] = 1
for i in icntl:
    print i 
女皇必胜 2024-12-22 04:08:48

您是否考虑过使用 SWIG 载体?

在你的头文件中:

typedef struct {
    int      icntl[40];
    double   cntl[15];
} some_struct_t;

然后,在你的 swig 文件中:

%module example
%include "carrays.i"  
// ...
%array_class(int, intArray);
%array_class(double, doubleArray);

Python 看起来像这样:

icntl = example.intArray(40)
cntl = example.doubleArray(15)
for i in range(0, 40):
    icntl[i] = i
for i in range(0, 15):
    cntl[i] = i
st = example.some_struct_t()
st.icntl = icntl
st.cntl = cntl

你仍然不能直接设置结构。我编写 python 包装器代码来隐藏样板文件。

array_class 仅适用于基本类型(int、double),如果您需要其他类型(例如 uint8_t),您需要使用 array_functions,它有更多的样板文件,但它们可以工作。

http://www.swig.org/Doc3.0/SWIGDocumentation.html#库_cararrays

Have you considered using SWIG carrays?

In your header file:

typedef struct {
    int      icntl[40];
    double   cntl[15];
} some_struct_t;

Then, in your swig file:

%module example
%include "carrays.i"  
// ...
%array_class(int, intArray);
%array_class(double, doubleArray);

The Python looks like this:

icntl = example.intArray(40)
cntl = example.doubleArray(15)
for i in range(0, 40):
    icntl[i] = i
for i in range(0, 15):
    cntl[i] = i
st = example.some_struct_t()
st.icntl = icntl
st.cntl = cntl

You still can't set the structs directly. I write python wrapper code to hide the boilerplate.

array_class only works with basic types (int, double), if you need something else (e.g. uint8_t) you need to use array_functions, which have even more boilerplate, but they work.

http://www.swig.org/Doc3.0/SWIGDocumentation.html#Library_carrays

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文