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