Python Types and C-Structures

Several new types are defined in the C-code. Most of these are accessible from Python, but a few are not exposed due to their limited use. Every new Python type has an associated :ctype:`PyObject *` with an internal structure that includes a pointer to a “method table” that defines how the new object behaves in Python. When you receive a Python object into C code, you always get a pointer to a :ctype:`PyObject` structure. Because a :ctype:`PyObject` structure is very generic and defines only :cmacro:`PyObject_HEAD`, by itself it is not very interesting. However, different objects contain more details after the :cmacro:`PyObject_HEAD` (but you have to cast to the correct type to access them — or use accessor functions or macros).

New Python Types Defined

Python types are the functional equivalent in C of classes in Python. By constructing a new Python type you make available a new object for Python. The ndarray object is an example of a new type defined in C. New types are defined in C by two basic steps:

  1. creating a C-structure (usually named :ctype:`Py{Name}Object`) that is binary- compatible with the :ctype:`PyObject` structure itself but holds the additional information needed for that particular object;
  2. populating the :ctype:`PyTypeObject` table (pointed to by the ob_type member of the :ctype:`PyObject` structure) with pointers to functions that implement the desired behavior for the type.

Instead of special method names which define behavior for Python classes, there are “function tables” which point to functions that implement the desired results. Since Python 2.2, the PyTypeObject itself has become dynamic which allows C types that can be “sub-typed “from other C-types in C, and sub-classed in Python. The children types inherit the attributes and methods from their parent(s).

There are two major new types: the ndarray ( :cdata:`PyArray_Type` ) and the ufunc ( :cdata:`PyUFunc_Type` ). Additional types play a supportive role: the :cdata:`PyArrayIter_Type`, the :cdata:`PyArrayMultiIter_Type`, and the :cdata:`PyArrayDescr_Type` . The :cdata:`PyArrayIter_Type` is the type for a flat iterator for an ndarray (the object that is returned when getting the flat attribute). The :cdata:`PyArrayMultiIter_Type` is the type of the object returned when calling broadcast (). It handles iteration and broadcasting over a collection of nested sequences. Also, the :cdata:`PyArrayDescr_Type` is the data-type-descriptor type whose instances describe the data. Finally, there are 21 new scalar-array types which are new Python scalars corresponding to each of the fundamental data types available for arrays. An additional 10 other types are place holders that allow the array scalars to fit into a hierarchy of actual Python types.

PyArray_Type

PyArrayDescr_Type

The :cdata:`PyArray_Type` typeobject implements many of the features of Python objects including the tp_as_number, tp_as_sequence, tp_as_mapping, and tp_as_buffer interfaces. The rich comparison (tp_richcompare) is also used along with new-style attribute lookup for methods (tp_methods) and properties (tp_getset). The :cdata:`PyArray_Type` can also be sub-typed.

Tip

The tp_as_number methods use a generic approach to call whatever function has been registered for handling the operation. The function PyNumeric_SetOps(..) can be used to register functions to handle particular mathematical operations (for all arrays). When the umath module is imported, it sets the numeric operations for all arrays to the corresponding ufuncs. The tp_str and tp_repr methods can also be altered using PyString_SetStringFunction(...).

PyUFunc_Type

PyArrayIter_Type

How to use an array iterator on a C-level is explained more fully in later sections. Typically, you do not need to concern yourself with the internal structure of the iterator object, and merely interact with it through the use of the macros :cfunc:`PyArray_ITER_NEXT` (it), :cfunc:`PyArray_ITER_GOTO` (it, dest), or :cfunc:`PyArray_ITER_GOTO1D` (it, index). All of these macros require the argument it to be a :ctype:`PyArrayIterObject *`.

PyArrayMultiIter_Type

PyArrayNeighborhoodIter_Type

PyArrayFlags_Type

ScalarArrayTypes

There is a Python type for each of the different built-in data types that can be present in the array Most of these are simple wrappers around the corresponding data type in C. The C-names for these types are :cdata:`Py{TYPE}ArrType_Type` where {TYPE} can be

Bool, Byte, Short, Int, Long, LongLong, UByte, UShort, UInt, ULong, ULongLong, Half, Float, Double, LongDouble, CFloat, CDouble, CLongDouble, String, Unicode, Void, and Object.

These type names are part of the C-API and can therefore be created in extension C-code. There is also a :cdata:`PyIntpArrType_Type` and a :cdata:`PyUIntpArrType_Type` that are simple substitutes for one of the integer types that can hold a pointer on the platform. The structure of these scalar objects is not exposed to C-code. The function :cfunc:`PyArray_ScalarAsCtype` (..) can be used to extract the C-type value from the array scalar and the function :cfunc:`PyArray_Scalar` (...) can be used to construct an array scalar from a C-value.

Other C-Structures

A few new C-structures were found to be useful in the development of NumPy. These C-structures are used in at least one C-API call and are therefore documented here. The main reason these structures were defined is to make it easy to use the Python ParseTuple C-API to convert from Python objects to a useful C-Object.

PyArray_Dims

PyArray_Chunk

PyArrayInterface

Internally used structures

Internally, the code uses some additional Python objects primarily for memory management. These types are not accessible directly from Python, and are not exposed to the C-API. They are included here only for completeness and assistance in understanding the code.