2011-11-13 19 views
6

dentro ho una struttura definita all'interno header.h che assomiglia:SWIG serie/python struttura

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

Quando init un oggetto con questa struttura, ho accesso a interi/doppie, ma non gli array .

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

Come accedere ai valori in lettura/scrittura?

risposta

6

Il modo più semplice per eseguire questa operazione è avvolgere gli array all'interno di uno struct, che può quindi fornire extra methods to meet the "subscriptable" requirements.

Ho messo insieme un piccolo esempio. Presuppone che stai usando C++, ma la versione C equivalente è abbastanza semplice da costruire da questo, richiede solo un po 'di ripetizione.

Il primo, intestazione C++ che ha il struct vogliamo avvolgere e un modello che usiamo per il confezionamento di array di dimensioni fisse:

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; 

nostra interfaccia SWIG corrispondente appare quindi qualcosa di simile:

%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>; 

Il trucco è che abbiamo usato %extend per fornire __getitem__ che è ciò che Python usa per le letture degli indici e __setitem__ per le scritture. (Potremmo anche aver fornito un __iter__ per rendere il tipo iterabile). Abbiamo anche dato lo specifico wraped_array s e vogliamo usare nomi univoci per fare in modo che SWIG li avvolga nell'output.

Con l'interfaccia in dotazione ora possiamo fare:

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

Si potrebbe anche trovare this approach utile/interessante come alternativa.

3

avrei fatto questo 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