]> granicus.if.org Git - python/commitdiff
A large contribution from Dave Kuhlman describing what each of the slots
authorFred Drake <fdrake@acm.org>
Wed, 15 Aug 2001 19:07:18 +0000 (19:07 +0000)
committerFred Drake <fdrake@acm.org>
Wed, 15 Aug 2001 19:07:18 +0000 (19:07 +0000)
in the type object is used for, for many of the more commonly used slots.
Thanks!

(But there is still a lot more to write on this topic.)
Markup and organizational changes by your friendly neighborhood
documentation czar.

Doc/ext/ext.tex

index 0ffec4631d9abf749ec69f2a63bd41d3f191a365..9b45172a2d8b35d7bb2a462ec86113ec093ae637 100644 (file)
@@ -1750,6 +1750,7 @@ implementation of CObjects (files \file{Include/cobject.h} and
 \chapter{Defining New Types
         \label{defining-new-types}}
 \sectionauthor{Michael Hudson}{mwh21@cam.ac.uk}
+\sectionauthor{Dave Kuhlman}{dkuhlman@rexx.com}
 
 As mentioned in the last chapter, Python allows the writer of an
 extension module to define new types that can be manipulated from
@@ -2065,6 +2066,7 @@ move to that directory and fire up Python --- you should be able to
 
 That wasn't so hard, was it?
 
+
 \section{Type Methods
          \label{dnt-type-methods}}
 
@@ -2111,18 +2113,42 @@ typedef struct _typeobject {
 
     char *tp_doc; /* Documentation string */
 
+    /* Assigned meaning in release 2.0 */
     /* call function for all accessible objects */
     traverseproc tp_traverse;
 
     /* delete references to contained objects */
     inquiry tp_clear;
 
+    /* Assigned meaning in release 2.1 */
     /* rich comparisons */
     richcmpfunc tp_richcompare;
 
     /* weak reference enabler */
     long tp_weaklistoffset;
 
+    /* Added in release 2.2 */
+    /* Iterators */
+    getiterfunc tp_iter;
+    iternextfunc tp_iternext;
+
+    /* Attribute descriptor and subclassing stuff */
+    struct PyMethodDef *tp_methods;
+    struct memberlist *tp_members;
+    struct getsetlist *tp_getset;
+    struct _typeobject *tp_base;
+    PyObject *tp_dict;
+    descrgetfunc tp_descr_get;
+    descrsetfunc tp_descr_set;
+    long tp_dictoffset;
+    initproc tp_init;
+    allocfunc tp_alloc;
+    newfunc tp_new;
+    destructor tp_free; /* Low-level free-memory routine */
+    PyObject *tp_bases;
+    PyObject *tp_mro; /* method resolution order */
+    PyObject *tp_defined;
+
 } PyTypeObject;
 \end{verbatim}
 
@@ -2130,8 +2156,14 @@ Now that's a \emph{lot} of methods.  Don't worry too much though - if
 you have a type you want to define, the chances are very good that you
 will only implement a handful of these.
 
-As you probably expect by now, I'm going to go over this line-by-line,
-saying a word about each field as we get to it.
+As you probably expect by now, we're going to go over this and give
+more information about the various handlers.  We won't go in the order
+they are defined in the structure, because there is a lot of
+historical baggage that impacts the ordering of the fields; be sure
+your type initializaion keeps the fields in the right order!  It's
+often easiest to find an example that includes all the fields you need
+(even if they're initialized to \code{0}) and then change the values
+to suit your new type.
 
 \begin{verbatim}
     char *tp_name; /* For printing */
@@ -2151,21 +2183,368 @@ for variable length structures (think: strings, lists) which is where
 the \cdata{tp_itemsize} field comes in.  This will be dealt with
 later.
 
-Now we come to the basic type methods - the ones most extension types
+\begin{verbatim}
+    char *tp_doc;
+\end{verbatim}
+
+Here you can put a string (or its address) that you want returned when
+the Python script references \code{obj.__doc__} to retrieve the
+docstring.
+   
+Now we come to the basic type methods---the ones most extension types
 will implement.
 
+
+\subsection{Finalization and De-allocation}
+
 \begin{verbatim}
     destructor tp_dealloc;
+\end{verbatim}
+
+This function is called when the reference count of the instance of
+your type is reduced to zero and the Python interpreter wants to
+reclaim it.  If your type has memory to free or other clean-up to
+perform, put it here.  The object itself needs to be freed here as
+well.  Here is an example of this function:
+
+\begin{verbatim}
+static void
+newdatatype_dealloc(newdatatypeobject * obj)
+{
+    free(obj->obj_UnderlyingDatatypePtr);
+    PyObject_DEL(obj);
+}
+\end{verbatim}
+
+
+\subsection{Object Representation}
+
+In Python, there are three ways to generate a textual representation
+of an object: the \function{repr()}\bifuncindex{repr} function (or
+equivalent backtick syntax), the \function{str()}\bifuncindex{str}
+function, and the \keyword{print} statement.  For most objects, the
+\keyword{print} statement is equivalent to the \function{str()}
+function, but it is possible to special-case printing to a
+\ctype{FILE*} if necessary; this should only be done if efficiency is
+identified as a problem and profiling suggests that creating a
+temporary string object to be written to a file is too expensive.
+
+These handlers are all optional, and most types at most need to
+implement the \member{tp_str} and \member{tp_repr} handlers.
+
+\begin{verbatim}
+    reprfunc tp_repr;
+    reprfunc tp_str;
     printfunc tp_print;
+\end{verbatim}
+
+The \member{tp_repr} handler should return a string object containing
+a representation of the instance for which it is called.  Here is a
+simple example:
+
+\begin{verbatim}
+static PyObject *
+newdatatype_repr(newdatatypeobject * obj)
+{
+    char buf[4096];
+    sprintf(buf, "Repr-ified_newdatatype{{size:%d}}",
+            obj->obj_UnderlyingDatatypePtr->size);
+    return PyString_FromString(buf);
+}
+\end{verbatim}
+
+If no \member{tp_repr} handler is specified, the interpreter will
+supply a representation that uses the type's \member{tp_name} and a
+uniquely-identifying value for the object.
+
+The \member{tp_str} handler is to \function{str()} what the
+\member{tp_repr} handler described above is to \function{repr()}; that
+is, it is called when Python code calls \function{str()} on an
+instance of your object.  It's implementation is very similar to the
+\member{tp_repr} function, but the resulting string is intended to be
+human consumption.  It \member{tp_str} is not specified, the
+\member{tp_repr} handler is used instead.
+
+Here is a simple example:
+
+\begin{verbatim}
+static PyObject *
+newdatatype_str(newdatatypeobject * obj)
+{
+    PyObject *pyString;
+    char buf[4096];
+    sprintf(buf, "Stringified_newdatatype{{size:%d}}",
+        obj->obj_UnderlyingDatatypePtr->size
+        );
+    pyString = PyString_FromString(buf);
+    return pyString;
+}
+\end{verbatim}
+
+The print function will be called whenever Python needs to "print" an
+instance of the type.  For example, if 'node' is an instance of type
+TreeNode, then the print function is called when Python code calls:
+
+\begin{verbatim}
+print node
+\end{verbatim}
+
+There is a flags argument and one flag, \constant{Py_PRINT_RAW}, and
+it suggests that you print without string quotes and possibly without
+interpreting escape sequences.
+
+The print function receives a file object as an argument. You will
+likely want to write to that file object.
+
+Here is a sampe print function:
+
+\begin{verbatim}
+static int
+newdatatype_print(newdatatypeobject *obj, FILE *fp, int flags)
+{
+    if (flags & Py_PRINT_RAW) {
+        fprintf(fp, "<{newdatatype object--size: %d}>",
+                obj->obj_UnderlyingDatatypePtr->size);
+    }
+    else {
+        fprintf(fp, "\"<{newdatatype object--size: %d}>\"",
+                obj->obj_UnderlyingDatatypePtr->size);
+    }
+    return 0;
+}
+\end{verbatim}
+
+
+\subsection{Attribute Management Functions}
+
+\begin{verbatim}
     getattrfunc tp_getattr;
     setattrfunc tp_setattr;
+\end{verbatim}
+
+The \member{tp_getattr} handle is called when the object requires an
+attribute look-up.  It is called in the same situations where the
+\method{__getattr__()} method of a class would be called.
+
+A likely way to handle this is (1) to implement a set of functions
+(such as \cfunction{newdatatype_getSize()} and
+\cfunction{newdatatype_setSize()} in the example below), (2) provide a
+method table listing these functions, and (3) provide a getattr
+function that returns the result of a lookup in that table.
+
+Here is an example:
+
+\begin{verbatim}
+static PyMethodDef newdatatype_methods[] = {
+    {"getSize", (PyCFunction)newdatatype_getSize, METH_VARARGS},
+    {"setSize", (PyCFunction)newdatatype_setSize, METH_VARARGS},
+    {NULL,      NULL}           /* sentinel */
+};
+
+static PyObject *
+newdatatype_getattr(newdatatypeobject *obj, char *name)
+{
+    return Py_FindMethod(newdatatype_methods, (PyObject *)obj, name);
+}
+\end{verbatim}
+
+The \member{tp_setattr} handler is called when the
+\method{__setattr__()} or \method{__delattr__()} method of a class
+instance would be called.  When an attribute should be deleted, the
+third parameter will be \NULL.  Here is an example that simply raises
+an exception; if this were really all you wanted, the
+\member{tp_setattr} handler should be set to \NULL.
+   
+\begin{verbatim}
+static int
+newdatatype_setattr(newdatatypeobject *obj, char *name, PyObject *v)
+{
+    char buf[1024];
+    sprintf(buf, "Set attribute not supported for attribute %s", name);
+    PyErr_SetString(PyExc_RuntimeError, buf);
+    return -1;
+}
+\end{verbatim}
+
+
+\subsection{Object Comparison}
+
+\begin{verbatim}
     cmpfunc tp_compare;
-    reprfunc tp_repr;
 \end{verbatim}
 
+The \member{tp_compare} handler is called when comparisons are needed
+are the object does not implement the specific rich comparison method
+which matches the requested comparison.  (It is always used if defined
+and the \cfunction{PyObject_Compare()} or \cfunction{PyObject_Cmp()}
+functions are used, or if \function{cmp()} is used from Python.)
+It is analogous to the \method{__cmp__()} method.  This function
+should return a negative integer if \var{obj1} is less than
+\var{obj2}, \code{0} if they are equal, and a positive integer if
+\var{obj1} is greater than
+\var{obj2}.
+
+Here is a sample implementation:
+
+\begin{verbatim}
+static int
+newdatatype_compare(newdatatypeobject * obj1, newdatatypeobject * obj2)
+{
+    long result;
+    if (obj1->obj_UnderlyingDatatypePtr->size <
+        obj2->obj_UnderlyingDatatypePtr->size) {
+        result = -1;
+    }
+    else if (obj1->obj_UnderlyingDatatypePtr->size >
+             obj2->obj_UnderlyingDatatypePtr->size) {
+        result = 1;
+    }
+    else {
+        result = 0;
+    }
+    return result;
+}
+\end{verbatim}
+
+
+\subsection{Abstract Protocol Support}
+
+\begin{verbatim}
+  tp_as_number;
+  tp_as_sequence;
+  tp_as_mapping;
+\end{verbatim}
+
+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 \ctype{PyNumberMethods},
+\ctype{PySequenceMethods}, or \ctype{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 \file{Objects}
+directory of the Python source distribution.
+
+
+\begin{verbatim}
+    hashfunc tp_hash;
+\end{verbatim}
+
+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:
+
+\begin{verbatim}
+static long
+newdatatype_hash(newdatatypeobject *obj)
+{
+    long result;
+    result = obj->obj_UnderlyingDatatypePtr->size;
+    result = result * 3;
+    return result;
+}
+\end{verbatim}
+
+\begin{verbatim}
+    ternaryfunc tp_call;
+\end{verbatim}
+
+This function is called when an instance of your datatype is "called",
+for example, if \code{obj1} is an instance of your datatype and the Python
+script contains \code{obj1('hello')}, the \member{tp_call} handler is
+invoked.
+
+This function takes three arguments:
+
+\begin{enumerate}
+  \item
+    \var{arg1} is the instance of the datatype which is the subject of
+    the call. If the call is \code{obj1('hello')}, then \var{arg1} is
+    \code{obj1}.
+
+  \item
+    \var{arg2} is a tuple containing the arguments to the call.  You
+    can use \cfunction{PyArg_ParseTuple()} to extract the arguments.
+
+  \item
+    \var{arg3} is a dictionary of keyword arguments that were passed.
+    If this is non-\NULL{} and you support keyword arguments, use
+    \cfunction{PyArg_ParseTupleAndKeywords()} to extract the
+    arguments.  If you do not want to support keyword arguments and
+    this is non-\NULL, raise a \exception{TypeError} with a message
+    saying that keyword arguments are not supported.
+\end{enumerate}
+       
+Here is a desultory example of the implementation of call function.
+
+\begin{verbatim}
+/* 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;
+    char buf[4096];
+    if (!PyArg_ParseTuple(args, "sss:call", &arg1, &arg2, &arg3)) {
+        return NULL;
+    }
+    sprintf(buf,
+            "Returning -- value: [%d] arg1: [%s] arg2: [%s] arg3: [%s]\n",
+            obj->obj_UnderlyingDatatypePtr->size,
+            arg1, arg2, arg3);
+    printf(buf);
+    return PyString_FromString(buf);
+}
+\end{verbatim}
+
+
+\subsection{More Suggestions}
+
+Remember that you can omit most of these functions, in which case you
+provide \code{0} as a value.
+
+In the \file{Objects} directory of the Python source distribution,
+there is a file \file{xxobject.c}, which is intended to be used as a
+template for the implementation of new types.  One useful strategy
+for implementing a new type is to copy and rename this file, then
+read the instructions at the top of it.
+
+There are type definitions for each of the functions you must
+provide.  They are in \file{object.h} in the Python include
+directory that comes with the source distribution of Python.
+
+In order to learn how to implement any specific method for your new
+datatype, do the following: Download and unpack the Python source
+distribution.  Go the the \file{Objects} directory, then search the
+C source files for \code{tp_} plus the function you want (for
+example, \code{tp_print} or \code{tp_compare}).  You will find
+examples of the function you want to implement.
+
+When you need to verify that the type of an object is indeed the
+object you are implementing and if you use xxobject.c as an starting
+template for your implementation, then there is a macro defined for
+this purpose. The macro definition will look something like this:
+
+\begin{verbatim}
+#define is_newdatatypeobject(v)  ((v)->ob_type == &Newdatatypetype)
+\end{verbatim}
+
+And, a sample of its use might be something like the following:
+
+\begin{verbatim}
+    if (!is_newdatatypeobject(objp1) {
+        PyErr_SetString(PyExc_TypeError, "arg #1 not a newdatatype");
+        return NULL;
+    }
+\end{verbatim}
 
-%\section{Attributes \& Methods
-%    \label{dnt-attrs-and-meths}}
+%For a reasonably extensive example, from which most of the snippits
+%above were taken, see \file{newdatatype.c} and \file{newdatatype.h}.
 
 
 \chapter{Building C and \Cpp{} Extensions on \UNIX{}