SWIG/python array inside structure

前端 未结 3 1780
南方客
南方客 2020-12-01 22:01

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

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


        
3条回答
  •  无人及你
    2020-12-01 23:03

    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 
    struct wrapped_array {
      Type data[N];
    };
    
    typedef struct {
        wrapped_array icntl;
        wrapped_array cntl;
        int      *irn, *jcn;
    } Test;
    

    Our corresponding SWIG interface then looks something like:

    %module test
    
    %{
    #include "test.h"
    #include 
    %}
    
    %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;
    %template (doubleArray15) wrapped_array;
    

    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 "", line 1, in 
      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.

提交回复
热议问题