On Wed, May 19, 2010 at 2:49 AM, Dag Sverre Seljebotn <
[email protected]> wrote:

> >
> > // In foo.h:
> > #define is_overridden_in_python(x) (Py_TYPE(((PyObject
> > *)x))->tp_dictoffset != 0)
> >
> > cdef extern from "foo.h:
> >    cdef bint is_overridden_in_python(object)
> >
> > Perhaps there's a Python C API function to do this as well.
> >
> BTW, there are features planned which would make all of this much much
> easier and friendlier, but don't expect them to show up soon.
>
>
That was a learning experience for me!  Since this is my first time diving
into buffers with Cython and also my first time using the NumPy C API, I was
hoping you guys could comment on how I implemented this---letting me know if
I have done anything really wrong.  I mostly followed the pseudocode
described here:
     #
http://docs.cython.org/src/userguide/pyrex_differences.html#cpdef-functions

The function is simple, but I think it successfully does what cpdef would
have done had I not been using buffers.  In particular, I am curious about
whether I should be doing Py_INCREF.  From what I read, since I am not using
PyArray_NewFromDescr<http://docs.scipy.org/doc/numpy/reference/c-api.array.html#PyArray_NewFromDescr>or
PyArray_New<http://docs.scipy.org/doc/numpy/reference/c-api.array.html#PyArray_New>there
is no need for me to increment the reference.  Also, please check my
macros:

// helper.h

#define could_be_overridden_in_python(x) (Py_TYPE((x))->tp_dictoffset != 0)

#define is_overridden_in_python(method, pfmethod) \
   ( !PyCFunction_Check(method) || \
     (PyCFunction_GET_FUNCTION(method) != (void *)&pfmethod ) \
   )

Note that I removed the explicit casts to PyObject * since Cython was
already inserting it.  Unwise?


Finally, here is my complete working example. Its a bit silly but it gets
the point across and could be useful to others.




import cython
cimport cython

import numpy as np
cimport numpy as np
from numpy cimport PyArray_DATA, npy_intp, NPY_DOUBLE

FTYPE = np.float
ITYPE = np.int
ctypedef np.float_t FTYPE_t
ctypedef np.int_t ITYPE_t

cdef extern from "numpy/arrayobject.h":
    cdef void import_array()
    object PyArray_SimpleNewFromData(int nd, npy_intp* dims, int typenum,
void* data)
    object PyArray_EMPTY(int nd, npy_intp* dims, int type_num, int fortran)

cdef extern from "helper.h":
    cdef bint could_be_overridden_in_python(object)
    cdef bint is_overridden_in_python(object, object)

import_array()

cdef class MyFunction:
    def quadruple(self, np.ndarray[FTYPE_t, ndim=1, mode="c"] x,
                        np.ndarray[FTYPE_t, ndim=1, mode="c"] out=None):
        if out is None:
            out = PyArray_EMPTY(1, <npy_intp *>(&x.shape[0]), NPY_DOUBLE, 0)
        self._quadruple(<FTYPE_t *>PyArray_DATA(x),
                        <FTYPE_t *>PyArray_DATA(out),
                        x.shape[0], 1)
        return out

    cdef void _quadruple(self, FTYPE_t *x, FTYPE_t *out, Py_ssize_t xlen,
int skip_dispatch=0):
        cdef np.ndarray[FTYPE_t, ndim=1, mode="c"] xarr
        cdef np.ndarray[FTYPE_t, ndim=1, mode="c"] outarr

        if not skip_dispatch and could_be_overridden_in_python(self):
            if is_overridden_in_python(self.quadruple,
MyFunction.quadruple):
                # Create arrays from pointer and call overridden method.
                xarr = PyArray_SimpleNewFromData(1, <npy_intp *>(&xlen),
NPY_DOUBLE, x)
                outarr = PyArray_SimpleNewFromData(1, <npy_intp *>(&xlen),
NPY_DOUBLE, out)
                self.quadruple(xarr, outarr)

        # Method definition
        cdef Py_ssize_t i
        for i in range(xlen):
            out[i] = 4 * x[i]










<http://docs.scipy.org/doc/numpy/reference/c-api.array.html#PyArray_New>
_______________________________________________
Cython-dev mailing list
[email protected]
http://codespeak.net/mailman/listinfo/cython-dev

Reply via email to