[Tutor] Reading arrays through an extension module

Michael P. Reilly arcege@shore.net
Thu, 4 Nov 1999 08:16:31 -0500 (EST)


> The code in question is attached at the bottom.  The first
> function (get_float_arr), after some hacking, seems to be
> working properly.  I take each element of the 1-D array and
> append them into a PyList.  I'm not certain this is a good
> approach but it gets me the numbers I want.

Since you know the dimension(s), it's better to create lists with that
size and populate, rather than creating an empty list and appending.
See below.

> The second function, however, is incomplete.  I have not
> been able to figure out how to build the 2-D array of floats
> into a python object (list?).  Could someone show me an
> efficent way to do this?  What if the array had arbitrarily
> larger dimensions?

(You don't say which dimension is which, so I'll make an assumption
that they are (row, col).  But it doesn't really matter; just switch as
needed.)

Like the first function, we know the dimensions, so the task is that
much easier.  It would end up as something similar to the Python code:
  l = [None] * index1
  for x in range(index1):
    l[x] = t = [None] * index2
    for y in range(index2):
      t[y] = tmparray[(index2*x)+y]
See below.

> Also, should I be using Py_DECREF in these functions?

The Py_BuildValue("N"...) does not increment the reference count, so
you do not want to decrement it.  BUT, since the length of the array is
given as the length of the list, you could just return the list instead
of a tuple containing the length and the list.  You should be more
conserned about the memory allocation of the C arrays being returned.

The error detection is incomplete, but I've inserted enough to get by. :)

Hope this helps,
  -Arcege

> ====================
> 
> /*
>  * Format of function (from documentation):
>  * xxx_get_float_arr( int ARG,
>  *                    float **tmp_float_arr,
>  *                    int *len );
>  *
>  * This function takes a single argument (ARG) and returns a one
>  * dimensional array of floats along with an int (len) which holds
>  * the length of the array.
>  */
> static PyObject *
> my_xxx_get_float_arr(self, args)
>     PyObject *self;
>     PyObject *args;
> {
>     int *ARG;
>     int ii;
>     int len;
>     float *tmp_float_arr_c;
>     PyObject *tmp_float_arr_py;
>     
>     if (!PyArg_ParseTuple(args, "i:get_float_arr", &ARG))
>         return NULL;
> 
>     xxx_get_float_arr(ARG, &tmp_float_arr_c, &len)
> 
>     tmp_float_arr_py = PyList_New(0);
>     for (ii=0; ii<len; ii++)
>     {
>         PyList_Append(tmp_float_arr_py, Py_BuildValue("f",
> tmp_float_arr_c[ii]));
>     }
>     /* Py_DECREF(tmp_float_arr_py); */
>     return Py_BuildValue("iN", len, tmp_float_arr_py);

Instead have:
      tmp_float_arr_py = PyList_New(len);
      if (tmp_float_arr_py != NULL)
          for (ii=0; ii<len; ii++)
              PyList_SetItem(tmp_float_arr_py, ii
                             PyFloat_AsDouble(temp_float_arr_c[ii]));
      return tmp_float_arr_py;

> }
> 
> /*
>  * Format of function (from documentation):
>  * xxx_get_float2_arr( int ARG,
>  *                     float ***tmp_float_arr,
>  *                     int *index1, int *index2 );
>  *
>  * This funtion takes a single argument (ARG) and returns a two
>  * dimensional array of floats along with two ints holding the
>  * dimensions of the array.
>  */
> static PyObject *
> my_xxx_get_float2_arr(self, args)
>     PyObject *self;
>     PyObject *args;
> {
>     int *ARG;
>     int index1, index2;
>     float *tmp_float2_arr_c;
>     PyObject *tmp_float2_arr_py;

      int x, y;
      PyObject *tmplist;

>     
>     if (!PyArg_ParseTuple(args, "i:get_float2_arr", &ARG))
>         return NULL;
> 
>     xxx_get_float2_arr(ARG, &tmp_float2_arr_c, &index1, &index2)

      if ((tmp_float2_arr_py = PyList_New(index1)) != NULL)
        { for (x=0; x<index1; x++)
            { if ((tmplist = PyList_New(index2)) != NULL)
                { PyList_SetItem(tmp_float2_arr_py, x, tmplist);
                  for (y=0; y<index2; y++)
                      PyList_SetItem(tmplist, y,
                          PyFloat_AsDouble(tmp_float2_arr_c[(index2*x)+y])
                        );
                }
              else
                { Py_DECREF(tmp_float2_arr_py);
                  return NULL;  /* raise NoMemoryError */
                }
            }
        }
      else
        return NULL; /* else raise NoMemoryError */

>     return Py_BuildValue("ii", index1, index2);  /* incomplete */
> }


-- 
------------------------------------------------------------------------
| Michael P. Reilly, Release Engineer | Email: arcege@shore.net        |
| Salem, Mass. USA  01970             |                                |
------------------------------------------------------------------------