[Pyrex] Access to nested structures and arrays

Pierre GM pgmdevlist at gmail.com
Fri Mar 16 17:29:07 UTC 2007


All,
I'm using Pyrex to write an interface between Python and an external C/fortran 
code. This code involves some nested structures whose individual elements I 
need to access from python.
I started to unwrap the nested structure, creating one extension type for each 
substructure. For example, I have this kind of definition in the ".pxd" part:

#............................
    ctypedef struct c_model "model":
        double span
        int    parametric[8]

   ctypedef struct c_nested "base":
        c_inputs inputs
        c_model model

#............................
Which becomes that in the ".pyx" part:

cdef class l_model:
    cdef c_loess.c_model *_base
    cdef long npar
    #.........
    property span:
        def __get__(self):
            return self._base.span
        def __set__(self, span):
            if span <= 0 or span >= 1:
                raise ValueError("Span should be comprised between 0 and 1!")
            self._base.span = span
    #.........
    property parametric_flags:
        def __get__(self):
            return boolarray_from_data(self.npar, 1, self._base.parametric)
        def __set__(self, paramf):
            cdef ndarray p_ndr
            cdef long *p_dat
            cdef int i
            p_ndr = numpy.array(paramf, copy=False, subok=True, 
dtype=numpy.int)
            p_dat = <long *>p_ndr.data
            for i from 0 <= i < min(self.npar, p_ndr.size - 1):
                self._base.parametric[i] = p_dat[i]
#............................
(where boolarray is a function that takes a C pointer and returns a numpy 
ndarray).

To initialize this extension type, I use this:
locmodel = l_model()
locmodel._base = &nested_structure._model
locmodel.npar = npar

where nested_structure is the underlying C base structure.

I tried to define a special __init__ method for l_model, that would take a 
pointer to the _model substructure and npar as arguments. That doesn't work, 
because _model cannot be transformed to a Python object.

First question:
When writing extension types, am I limited to use only Python objects as 
arguments of __init__ ?

Using properties was the quickest way I found to access the elements of the 
underlying C substructure, but that looks a bit bloated: I'm putting layers 
over layers.

Second question:
isn't there a better way than that ?

Finally, using properties is fine up to a point. Some elements of the 
substructures are pointers to C arrays (for example, parametric in c_model). 
I need to read and write to these arrays. Reading is fine, but I have a 
problem with writing: the __set__ method I use  lets me write the whole array 
at once, but I'd like to modify some individual elements.
For example:
>>>X = l_model.parametric_flags
X is a ndarray, everything's fine
>>>l_model.parametric_flags = X[::-1]
I'm setting the whole array at once, so that's fine as well. But now,
>>>l_model.parametric_flags[0] = True
will NOT update the first element of the underlying C substructure, 
c_model.parametric, as I'd like it to.

Third question:
how can I modify the underlying C array from Python ?


I hope it doesn't sound too confusing. I'm still very new to C and Pyrex, I'm 
sure you'll be lenient.

Thanks a lot in advance for any idea/comments.









More information about the Pyrex mailing list