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:
- 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;
- 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¶
See also
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.