簡體   English   中英

SWIG / python數組內部結構

[英]SWIG/python array inside structure

我在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

如何訪問讀/寫中的值?

最簡單的方法是將數組包裝在struct ,然后可以提供額外的方法來滿足“可訂閱”的要求

我整理了一個小例子。 假定您使用的是C ++,但是從中構造等效的C版本相當簡單,只需要重復一下即可。

首先,具有要包裝的struct的C ++標頭和用於包裝固定大小數組的模板:

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__用於寫入的內容。 (我們也可以提供__iter__來使類型可迭代)。 我們還提供了特定的wraped_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

您可能還會發現此方法很有用/有趣,可以作為替代方法。

我會在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 

您是否考慮過使用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#Library_carrays

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM