Python supports a variety of abstract `protocols;' the specific interfaces provided to use these interfaces are documented in the Python/C API Reference Manual in the chapter ``Abstract Objects Layer.''
A number of these abstract interfaces were defined early in the development of the Python implementation. In particular, the number, mapping, and sequence protocols have been part of Python since the beginning. Other protocols have been added over time. For protocols which depend on several handler routines from the type implementation, the older protocols have been defined as optional blocks of handlers referenced by the type object, while newer protocols have been added using additional slots in the main type object, with a flag bit being set to indicate that the slots are present. (The flag bit does not indicate that the slot values are non-NULL.)
PyNumberMethods tp_as_number; PySequenceMethods tp_as_sequence; PyMappingMethods tp_as_mapping;
If you wish your object to be able to act like a number, a sequence, or a mapping object, then you place the address of a structure that implements the C type PyNumberMethods, PySequenceMethods, or PyMappingMethods, respectively. It is up to you to fill in this structure with appropriate values. You can find examples of the use of each of these in the Objects directory of the Python source distribution.
hashfunc tp_hash;
This function, if you choose to provide it, should return a hash number for an instance of your datatype. Here is a moderately pointless example:
static long newdatatype_hash(newdatatypeobject *obj) { long result; result = obj->obj_UnderlyingDatatypePtr->size; result = result * 3; return result; }
ternaryfunc tp_call;
This function is called when an instance of your datatype is "called",
for example, if obj1
is an instance of your datatype and the Python
script contains obj1('hello')
, the tp_call handler is
invoked.
This function takes three arguments:
obj1('hello')
, then arg1 is
obj1
.
Here is a desultory example of the implementation of the call function.
/* Implement the call function. * obj1 is the instance receiving the call. * obj2 is a tuple containing the arguments to the call, in this * case 3 strings. */ static PyObject * newdatatype_call(newdatatypeobject *obj, PyObject *args, PyObject *other) { PyObject *result; char *arg1; char *arg2; char *arg3; if (!PyArg_ParseTuple(args, "sss:call", &arg1, &arg2, &arg3)) { return NULL; } result = PyString_FromFormat( "Returning -- value: [\%d] arg1: [\%s] arg2: [\%s] arg3: [\%s]\n", obj->obj_UnderlyingDatatypePtr->size, arg1, arg2, arg3); printf("\%s", PyString_AS_STRING(result)); return result; }
XXX some fields need to be added here...
/* Added in release 2.2 */ /* Iterators */ getiterfunc tp_iter; iternextfunc tp_iternext;
These functions provide support for the iterator protocol. Any object
which wishes to support iteration over it's contents (which may be
generated during iteration) must implement the tp_iter
handler. Objects which are returned by a tp_iter
handler must
implement both the tp_iter
and tp_iternext
handlers.
Both handlers take exactly one parameter, the instance for which they
are being called, and return a new reference. In the case of an
error, they should set an exception and return NULL.
For an object which represents an iterable collection, the
tp_iter
handler must return an iterator object. The iterator
object is responsible for maintaining the state of the iteration. For
collections which can support multiple iterators which do not
interfere with each other (as lists and tuples do), a new iterator
should be created and returned. Objects which can only be iterated
over once (usually due to side effects of iteration) should implement
this handler by returning a new reference to themselves, and should
also implement the tp_iternext
handler. File objects are an
example of such an iterator.
Iterator objects should implement both handlers. The tp_iter
handler should return a new reference to the iterator (this is the
same as the tp_iter
handler for objects which can only be
iterated over destructively). The tp_iternext
handler should
return a new reference to the next object in the iteration if there is
one. If the iteration has reached the end, it may return NULL
without setting an exception or it may set StopIteration;
avoiding the exception can yield slightly better performance. If an
actual error occurs, it should set an exception and return NULL.
See About this document... for information on suggesting changes.