Skip to content

Instantly share code, notes, and snippets.

@jdfr
Last active August 29, 2015 14:20
Show Gist options
  • Save jdfr/688507524b6b4163e4c0 to your computer and use it in GitHub Desktop.
Save jdfr/688507524b6b4163e4c0 to your computer and use it in GitHub Desktop.
Numpy's PyArray_New for dummies

When it comes to usign the Numpy C API to create arrays, there are plenty of resources to use the simpler functions, such as the PyArray_SimpleNewXXX() series. To use the most generic ones, you are supposed to be fairly well versed in Numpy. Unfortunately, there are functions of intermediate complexity, and resources for these are scarce.

Today, I had to create a Numpy array as a view (without copying data) of some fields in a vector of structs. Clearly, not a job for the PyArray_SimpleNewXXX() functions, but for PyArray_New(). Besides basic info such as the buffer, the type, and the strides, this function requires some arcane arguments, such as the PyTypeObject* subtype.

For the life of me, I could not figure out what to pass to the function as that argument. The Numpy sources were of no help. since they passed a pointer to a function (&PyArray_Type) as that argument (?!?!?!). After much experimentation and frustration, I found the answer to my predicament in this thread:

https://groups.google.com/forum/#!topic/cython-users/fFBiCCwblD0

Argh!!!! Just np.ndarray!!!!!! So simple, yet so cryptic! I am sure that the answer to this question was somehow in the Numpy docs, but WHY NOT PUT AN EXAMPLE CALL FOR EACH FUNCTION?

Anyway, let's see a snippet of code with the solution...

#cython code
cimport numpy as cnp
import numpy as np
cnp.import_array()
cdef extern from "numpy/ndarraytypes.h" nogil:
int NPY_ARRAY_CARRAY
cimport cpython.ref as ref
#"parent" is the owner of "data"
cdef cnp.ndarray get2DArrayAsView(object parent, void *data, cdef cnp.npy_intp *strides, cdef cnp.npy_intp *dims):
cdef cnp.ndarray result = cnp.PyArray_New(np.ndarray, 2, dims, cnp.NPY_INT64, strides,
data, -1, NPY_ARRAY_CARRAY, <object>NULL)
#result.base is of type PyObject*, so no reference counting with this assignment
result.base = <ref.PyObject*>parent
ref.Py_INCREF(parent) #so, make sure that "result" owns a reference to "parent"
return result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment