User guide

NumPy User Guide, Release 1.9.0
int PyUFunc_RegisterLoopForType( PyUFuncObject
*
ufunc,
int usertype, PyUFuncGenericFunction function, int
*
arg_types, void
*
data)
ufunc
The ufunc to attach this loop to.
usertype
The user-defined type this loop should be indexed under. This number must be a user-defined type or
an error occurs.
function
The ufunc inner 1-d loop. This function must have the signature as explained in Section 3 .
arg_types
(optional) If given, this should contain an array of integers of at least size ufunc.nargs containing the
data-types expected by the loop function. The data will be copied into a NumPy-managed structure
so the memory for this argument should be deleted after calling this function. If this is NULL, then
it will be assumed that all data-types are of type usertype.
data
(optional) Specify any optional data needed by the function which will be passed when the function
is called.
5.4.3 Subtyping the ndarray in C
One of the lesser-used features that has been lurking in Python since 2.2 is the ability to sub-class types in C. This
facility is one of the important reasons for basing NumPy off of the Numeric code-base which was already in C. A
sub-type in C allows much more flexibility with regards to memory management. Sub-typing in C is not difficult even
if you have only a rudimentary understanding of how to create new types for Python. While it is easiest to sub-type
from a single parent type, sub-typing from multiple parent types is also possible. Multiple inheritence in C is generally
less useful than it is in Python because a restriction on Python sub-types is that they have a binary compatible memory
layout. Perhaps for this reason, it is somewhat easier to sub-type from a single parent type.
All C-structures corresponding to Python objects must begin with PyObject_HEAD (or PyObject_VAR_HEAD).
In the same way, any sub-type must have a C-structure that begins with exactly the same memory layout as the parent
type (or all of the parent types in the case of multiple-inheritance). The reason for this is that Python may attempt to
access a member of the sub-type structure as if it had the parent structure ( i.e. it will cast a given pointer to a pointer
to the parent structure and then dereference one of it’s members). If the memory layouts are not compatible, then this
attempt will cause unpredictable behavior (eventually leading to a memory violation and program crash).
One of the elements in PyObject_HEAD is a pointer to a type-object structure. A new Python type is created by
creating a new type-object structure and populating it with functions and pointers to describe the desired behavior
of the type. Typically, a new C-structure is also created to contain the instance-specific information needed for each
object of the type as well. For example, &PyArray_Type is a pointer to the type-object table for the ndarray
while a PyArrayObject
*
variable is a pointer to a particular instance of an ndarray (one of the members of
the ndarray structure is, in turn, a pointer to the type- object table &PyArray_Type). Finally PyType_Ready
(<pointer_to_type_object>) must be called for every new Python type.
Creating sub-types
To create a sub-type, a similar proceedure must be followed except only behaviors that are different require new entries
in the type- object structure. All other entires can be NULL and will be filled in by PyType_Ready with appropriate
functions from the parent type(s). In particular, to create a sub-type in C follow these steps:
5.4. Beyond the Basics 103