summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2004-07-15 04:05:59 (GMT)
committerTim Peters <tim.peters@gmail.com>2004-07-15 04:05:59 (GMT)
commiteda29306b34303af2b79366c12f54a223029c165 (patch)
tree1215e26d073dba84614c4355d3335b852a3f0bf6
parent89ba1fff170f9e5de6f8c9c4ad598931c69492e8 (diff)
downloadcpython-eda29306b34303af2b79366c12f54a223029c165.zip
cpython-eda29306b34303af2b79366c12f54a223029c165.tar.gz
cpython-eda29306b34303af2b79366c12f54a223029c165.tar.bz2
Formalize that the Py_VISIT macro requires that the tp_traverse
implementation it's used in must give its arguments specific names.
-rw-r--r--Doc/api/newtypes.tex11
-rw-r--r--Doc/ext/newtypes.tex71
-rw-r--r--Include/objimpl.h6
3 files changed, 49 insertions, 39 deletions
diff --git a/Doc/api/newtypes.tex b/Doc/api/newtypes.tex
index 2b58cd9..deb4ac1 100644
--- a/Doc/api/newtypes.tex
+++ b/Doc/api/newtypes.tex
@@ -1664,13 +1664,14 @@ The \member{tp_traverse} handler must have the following type:
\end{ctypedesc}
To simplify writing \member{tp_traverse} handlers, a
-\cfunction{Py_VISIT()} is provided:
+\cfunction{Py_VISIT()} macro is provided. In order to use this macro,
+the \member{tp_traverse} implementation must name its arguments
+exactly \var{visit} and \var{arg}:
\begin{cfuncdesc}{void}{Py_VISIT}{PyObject *o}
- Call the \var{visit} for \var{o} with \var{arg}. If \var{visit}
- returns a non-zero value, then return it. Using this macro,
- \member{tp_traverse} handlers look like:
-
+ Call the \var{visit} callback, with arguments \var{o} and \var{arg}.
+ If \var{visit} returns a non-zero value, then return it. Using this
+ macro, \member{tp_traverse} handlers look like:
\begin{verbatim}
static int
diff --git a/Doc/ext/newtypes.tex b/Doc/ext/newtypes.tex
index 616b1b9..6864853 100644
--- a/Doc/ext/newtypes.tex
+++ b/Doc/ext/newtypes.tex
@@ -106,7 +106,7 @@ Now if you go and look up the definition of \ctype{PyTypeObject} in
\file{object.h} you'll see that it has many more fields that the
definition above. The remaining fields will be filled with zeros by
the C compiler, and it's common practice to not specify them
-explicitly unless you need them.
+explicitly unless you need them.
This is so important that we're going to pick the top of it apart still
further:
@@ -149,7 +149,7 @@ TypeError: cannot add type "noddy.Noddy" to string
\end{verbatim}
Note that the name is a dotted name that includes both the module name
-and the name of the type within the module. The module in this case is
+and the name of the type within the module. The module in this case is
\module{noddy} and the type is \class{Noddy}, so we set the type name
to \class{noddy.Noddy}.
@@ -180,7 +180,7 @@ This has to do with variable length objects like lists and strings.
Ignore this for now.
Skipping a number of type methods that we don't provide, we set the
-class flags to \constant{Py_TPFLAGS_DEFAULT}.
+class flags to \constant{Py_TPFLAGS_DEFAULT}.
\begin{verbatim}
Py_TPFLAGS_DEFAULT, /*tp_flags*/
@@ -197,8 +197,8 @@ We provide a doc string for the type in \member{tp_doc}.
Now we get into the type methods, the things that make your objects
different from the others. We aren't going to implement any of these
-in this version of the module. We'll expand this example later to
-have more interesting behavior.
+in this version of the module. We'll expand this example later to
+have more interesting behavior.
For now, all we want to be able to do is to create new \class{Noddy}
objects. To enable object creation, we have to provide a
@@ -268,7 +268,7 @@ Of course, the current Noddy type is pretty uninteresting. It has no
data and doesn't do anything. It can't even be subclassed.
\subsection{Adding data and methods to the Basic example}
-
+
Let's expend the basic example to add some data and methods. Let's
also make the type usable as a base class. We'll create
a new module, \module{noddy2} that adds these capabilities:
@@ -351,7 +351,7 @@ Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_DECREF(self);
return NULL;
}
-
+
self->last = PyString_FromString("");
if (self->last == NULL)
{
@@ -417,10 +417,10 @@ Noddy_init(Noddy *self, PyObject *args, PyObject *kwds)
static char *kwlist[] = {"first", "last", "number", NULL};
- if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
- &first, &last,
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
+ &first, &last,
&self->number))
- return -1;
+ return -1;
if (first) {
tmp = self->first;
@@ -488,7 +488,7 @@ this?
garbage collection, there are calls that can be made to ``untrack''
the object from garbage collection, however, these calls are
advanced and not covered here.}
-\item
+\item
\end{itemize}
@@ -527,7 +527,7 @@ sure the members are initialized to non-\NULL{} values, the members can
be set to \NULL{} if the attributes are deleted.
We define a single method, \method{name}, that outputs the objects
-name as the concatenation of the first and last names.
+name as the concatenation of the first and last names.
\begin{verbatim}
static PyObject *
@@ -558,7 +558,7 @@ Noddy_name(Noddy* self)
result = PyString_Format(format, args);
Py_DECREF(args);
-
+
return result;
}
\end{verbatim}
@@ -656,16 +656,16 @@ Noddy_setfirst(Noddy *self, PyObject *value, void *closure)
PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
return -1;
}
-
+
if (! PyString_Check(value)) {
- PyErr_SetString(PyExc_TypeError,
+ PyErr_SetString(PyExc_TypeError,
"The first attribute value must be a string");
return -1;
}
-
+
Py_DECREF(self->first);
Py_INCREF(value);
- self->first = value;
+ self->first = value;
return 0;
}
@@ -687,11 +687,11 @@ We create an array of \ctype{PyGetSetDef} structures:
\begin{verbatim}
static PyGetSetDef Noddy_getseters[] = {
- {"first",
+ {"first",
(getter)Noddy_getfirst, (setter)Noddy_setfirst,
"first name",
NULL},
- {"last",
+ {"last",
(getter)Noddy_getlast, (setter)Noddy_setlast,
"last name",
NULL},
@@ -705,7 +705,7 @@ and register it in the \member{tp_getset} slot:
Noddy_getseters, /* tp_getset */
\end{verbatim}
-to register out attribute getters and setters.
+to register out attribute getters and setters.
The last item in a \ctype{PyGetSetDef} structure is the closure
mentioned above. In this case, we aren't using the closure, so we just
@@ -737,10 +737,10 @@ Noddy_init(Noddy *self, PyObject *args, PyObject *kwds)
static char *kwlist[] = {"first", "last", "number", NULL};
- if (! PyArg_ParseTupleAndKeywords(args, kwds, "|SSi", kwlist,
- &first, &last,
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "|SSi", kwlist,
+ &first, &last,
&self->number))
- return -1;
+ return -1;
if (first) {
tmp = self->first;
@@ -838,11 +838,11 @@ For each subobject that can participate in cycles, we need to call the
\cfunction{visit()} function, which is passed to the traversal method.
The \cfunction{visit()} function takes as arguments the subobject and
the extra argument \var{arg} passed to the traversal method. It
-returns an integer value that must be returned if it is non-zero.
+returns an integer value that must be returned if it is non-zero.
-Python 2.4 and higher provide a \cfunction{Py_VISIT()} that automates
-calling visit functions. With \cfunction{Py_VISIT()}, the
+Python 2.4 and higher provide a \cfunction{Py_VISIT()} macro that automates
+calling visit functions. With \cfunction{Py_VISIT()},
\cfunction{Noddy_traverse()} can be simplified:
@@ -856,12 +856,17 @@ Noddy_traverse(Noddy *self, visitproc visit, void *arg)
}
\end{verbatim}
+\note{Note that the \member{tp_traverse} implementation must name its
+ arguments exactly \var{visit} and \var{arg} in order to use
+ \cfunction{Py_VISIT()}. This is to encourage uniformity
+ across these boring implementations.}
+
We also need to provide a method for clearing any subobjects that can
participate in cycles. We implement the method and reimplement the
deallocator to use it:
\begin{verbatim}
-static int
+static int
Noddy_clear(Noddy *self)
{
PyObject *tmp;
@@ -903,7 +908,7 @@ the careful decrementing of reference counts. With
simplified:
\begin{verbatim}
-static int
+static int
Noddy_clear(Noddy *self)
{
Py_CLEAR(self->first);
@@ -973,7 +978,7 @@ later.
Here you can put a string (or its address) that you want returned when
the Python script references \code{obj.__doc__} to retrieve the
doc string.
-
+
Now we come to the basic type methods---the ones most extension types
will implement.
@@ -1281,7 +1286,7 @@ to retrieve the descriptor from the class object, and get the
doc string using its \member{__doc__} attribute.
As with the \member{tp_methods} table, a sentinel entry with a
-\member{name} value of \NULL{} is required.
+\member{name} value of \NULL{} is required.
% XXX Descriptors need to be explained in more detail somewhere, but
@@ -1345,7 +1350,7 @@ 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)
@@ -1389,7 +1394,7 @@ static int
newdatatype_compare(newdatatypeobject * obj1, newdatatypeobject * obj2)
{
long result;
-
+
if (obj1->obj_UnderlyingDatatypePtr->size <
obj2->obj_UnderlyingDatatypePtr->size) {
result = -1;
@@ -1489,7 +1494,7 @@ This function takes three arguments:
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 the call function.
\begin{verbatim}
diff --git a/Include/objimpl.h b/Include/objimpl.h
index 649d1bc..5707e50 100644
--- a/Include/objimpl.h
+++ b/Include/objimpl.h
@@ -302,7 +302,11 @@ PyAPI_FUNC(void) PyObject_GC_Del(void *);
( (type *) _PyObject_GC_NewVar((typeobj), (n)) )
-/* Utility macro to help write tp_traverse functions */
+/* Utility macro to help write tp_traverse functions.
+ * To use this macro, the tp_traverse function must name its arguments
+ * "visit" and "arg". This is intended to keep tp_traverse functions
+ * looking as much alike as possible.
+ */
#define Py_VISIT(op) \
do { \
if (op) { \