2.2.5 Abstract Protocol Support
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. For newer protocols there are additional slots in the main type object, with a flag bit being set to indicate that the slots are present and should be checked by the interpreter. (The flag bit does not indicate that the slot values are non-NULL. The flag may be set to indicate the presence of a slot, but a slot may still be unfilled.)
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 data type. 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 data type is "called",
for example, if obj1
is an instance of your data type and the Python
script contains obj1('hello')
, the tp_call handler is
invoked.
This function takes three arguments:
- arg1 is the instance of the data type which is the subject of
the call. If the call is
obj1('hello')
, then arg1 isobj1
. - arg2 is a tuple containing the arguments to the call. You
can use PyArg_ParseTuple() to extract the arguments.
- arg3 is a dictionary of keyword arguments that were passed. If this is non-NULL and you support keyword arguments, use PyArg_ParseTupleAndKeywords() to extract the arguments. If you do not want to support keyword arguments and this is non-NULL, raise a TypeError with a message saying that keyword arguments are not supported.
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 its 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.