jah wrote: > On Wed, May 19, 2010 at 2:49 AM, Dag Sverre Seljebotn > <[email protected] <mailto:[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: Yes, the NumPy functions are a bit strange regarding references, but the ones you use don't take any Python objects so you're safe. It all looks good to me.
What's performance hit do you get from the extra check, is it noticeable? > > // 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? No, that's OK. > > > 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 <http://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) It's a bit more readable to simply pass "x.shape" without &..[0] and the cast, you should be able to do that. Anyway, looks great! Dag Sverre _______________________________________________ Cython-dev mailing list [email protected] http://codespeak.net/mailman/listinfo/cython-dev
