question: numarray c extension error handling?

David M. Cooke cookedm+news at physics.mcmaster.ca
Wed Mar 10 16:57:42 EST 2004


At some point, "Russell E. Owen" <no at spam.invalid> wrote:

> I'm writing a C extension for numarray and am puzzled about the idiom 
> for error handling.
>
> The documentation seems to say one should always decref an array after 
> calling  NA_InputArray, etc., to convert numarray args to C arrays. 
>
> However, the example and also the numarray code suggests that it's OK to 
> return early via (for example) PyErr_Format without doing the DECREF. 
> For example, I have appended a very abbreviated version of the sample 
> code.
>
> Comments? I'll plow ahead and follow the example (i.e. with early 
> return) but I was wondering if anyone knew why this was OK. Perhaps I 
> should put in a request to the numarray project for a clarification in 
> the documentation.
>
> -- Russell
>
> static PyObject * Py_Convolve1d(PyObject *obj, PyObject *args)
> {
>     PyObject   *okernel,...;
>     PyArrayObject *kernel...;
>
>     if (!PyArg_ParseTuple(args, "OO|O", &okernel, ...))
>         return PyErr_Format(_convolveError, 
>                     "Convolve1d: Invalid parameters.");

This is ok; if PyArg_ParseTuple is NULL, no objects are created (or
INCREF'd). Also, if it's not NULL, okernel is a borrowed reference;
you shouldn't DECREF it.

>
>     /* Align, Byteswap, Contiguous, Typeconvert */
>     kernel  = NA_IoArray(okernel, tFloat64, C_ARRAY);
> ...
>     if (!kernel...)
>         return PyErr_Format( _convolveError, 
>                  "Convolve1d: error converting array inputs.");

This is also ok (assuming there is nothing between this and the above
which makes a reference to objects). If NA_IoArray returns NULL,
there isn't anything to DECREF.

> ...
>     Py_XDECREF(kernel);
> ...
> }

Personally, I write it like this:

static PyObject * Py_Convolve1d(PyObject *obj, PyObject *args)
{
    PyObject   *okernel,...;
    PyArrayObject *kernel = NULL;

    if (!PyArg_ParseTuple(args, "OO|O", &okernel, ...)) {
        PyErr_Format(_convolveError,
                    "Convolve1d: Invalid parameters.");
        goto error;
    }
    kernel  = NA_IoArray(okernel, tFloat64, C_ARRAY);
    if (!kernel...) {
        PyErr_Format( _convolveError, 
                 "Convolve1d: error converting array inputs.");
        goto error;
    }

    ...more stuff...

    Py_XDECREF(kernel)
    return the result
error:
    Py_XDECREF(kernel)
    return NULL;
}

Notice that kernel was initialized to NULL, so Py_XDECREF will work in
all cases. Clean error-handling code like this is one of the few
places I use goto in C. You now have only two exits out of the
function, at the bottom, and so it's _much_ easier to keep track of
what needs to be DECREF'd.

-- 
|>|\/|<
/--------------------------------------------------------------------------\
|David M. Cooke
|cookedm(at)physics(dot)mcmaster(dot)ca



More information about the Python-list mailing list