Kaydet (Commit) eda29306 authored tarafından Tim Peters's avatar Tim Peters

Formalize that the Py_VISIT macro requires that the tp_traverse

implementation it's used in must give its arguments specific names.
üst 89ba1fff
...@@ -1664,13 +1664,14 @@ The \member{tp_traverse} handler must have the following type: ...@@ -1664,13 +1664,14 @@ The \member{tp_traverse} handler must have the following type:
\end{ctypedesc} \end{ctypedesc}
To simplify writing \member{tp_traverse} handlers, a 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} \begin{cfuncdesc}{void}{Py_VISIT}{PyObject *o}
Call the \var{visit} for \var{o} with \var{arg}. If \var{visit} Call the \var{visit} callback, with arguments \var{o} and \var{arg}.
returns a non-zero value, then return it. Using this macro, If \var{visit} returns a non-zero value, then return it. Using this
\member{tp_traverse} handlers look like: macro, \member{tp_traverse} handlers look like:
\begin{verbatim} \begin{verbatim}
static int static int
......
...@@ -106,7 +106,7 @@ Now if you go and look up the definition of \ctype{PyTypeObject} in ...@@ -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 \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 definition above. The remaining fields will be filled with zeros by
the C compiler, and it's common practice to not specify them 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 This is so important that we're going to pick the top of it apart still
further: further:
...@@ -149,7 +149,7 @@ TypeError: cannot add type "noddy.Noddy" to string ...@@ -149,7 +149,7 @@ TypeError: cannot add type "noddy.Noddy" to string
\end{verbatim} \end{verbatim}
Note that the name is a dotted name that includes both the module name 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 \module{noddy} and the type is \class{Noddy}, so we set the type name
to \class{noddy.Noddy}. to \class{noddy.Noddy}.
...@@ -180,7 +180,7 @@ This has to do with variable length objects like lists and strings. ...@@ -180,7 +180,7 @@ This has to do with variable length objects like lists and strings.
Ignore this for now. Ignore this for now.
Skipping a number of type methods that we don't provide, we set the 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} \begin{verbatim}
Py_TPFLAGS_DEFAULT, /*tp_flags*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/
...@@ -197,8 +197,8 @@ We provide a doc string for the type in \member{tp_doc}. ...@@ -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 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 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 in this version of the module. We'll expand this example later to
have more interesting behavior. have more interesting behavior.
For now, all we want to be able to do is to create new \class{Noddy} 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 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 ...@@ -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. data and doesn't do anything. It can't even be subclassed.
\subsection{Adding data and methods to the Basic example} \subsection{Adding data and methods to the Basic example}
Let's expend the basic example to add some data and methods. Let's 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 also make the type usable as a base class. We'll create
a new module, \module{noddy2} that adds these capabilities: a new module, \module{noddy2} that adds these capabilities:
...@@ -351,7 +351,7 @@ Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ...@@ -351,7 +351,7 @@ Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_DECREF(self); Py_DECREF(self);
return NULL; return NULL;
} }
self->last = PyString_FromString(""); self->last = PyString_FromString("");
if (self->last == NULL) if (self->last == NULL)
{ {
...@@ -417,10 +417,10 @@ Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) ...@@ -417,10 +417,10 @@ Noddy_init(Noddy *self, PyObject *args, PyObject *kwds)
static char *kwlist[] = {"first", "last", "number", NULL}; static char *kwlist[] = {"first", "last", "number", NULL};
if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
&first, &last, &first, &last,
&self->number)) &self->number))
return -1; return -1;
if (first) { if (first) {
tmp = self->first; tmp = self->first;
...@@ -488,7 +488,7 @@ this? ...@@ -488,7 +488,7 @@ this?
garbage collection, there are calls that can be made to ``untrack'' garbage collection, there are calls that can be made to ``untrack''
the object from garbage collection, however, these calls are the object from garbage collection, however, these calls are
advanced and not covered here.} advanced and not covered here.}
\item \item
\end{itemize} \end{itemize}
...@@ -527,7 +527,7 @@ sure the members are initialized to non-\NULL{} values, the members can ...@@ -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. be set to \NULL{} if the attributes are deleted.
We define a single method, \method{name}, that outputs the objects 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} \begin{verbatim}
static PyObject * static PyObject *
...@@ -558,7 +558,7 @@ Noddy_name(Noddy* self) ...@@ -558,7 +558,7 @@ Noddy_name(Noddy* self)
result = PyString_Format(format, args); result = PyString_Format(format, args);
Py_DECREF(args); Py_DECREF(args);
return result; return result;
} }
\end{verbatim} \end{verbatim}
...@@ -656,16 +656,16 @@ Noddy_setfirst(Noddy *self, PyObject *value, void *closure) ...@@ -656,16 +656,16 @@ Noddy_setfirst(Noddy *self, PyObject *value, void *closure)
PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
return -1; return -1;
} }
if (! PyString_Check(value)) { if (! PyString_Check(value)) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"The first attribute value must be a string"); "The first attribute value must be a string");
return -1; return -1;
} }
Py_DECREF(self->first); Py_DECREF(self->first);
Py_INCREF(value); Py_INCREF(value);
self->first = value; self->first = value;
return 0; return 0;
} }
...@@ -687,11 +687,11 @@ We create an array of \ctype{PyGetSetDef} structures: ...@@ -687,11 +687,11 @@ We create an array of \ctype{PyGetSetDef} structures:
\begin{verbatim} \begin{verbatim}
static PyGetSetDef Noddy_getseters[] = { static PyGetSetDef Noddy_getseters[] = {
{"first", {"first",
(getter)Noddy_getfirst, (setter)Noddy_setfirst, (getter)Noddy_getfirst, (setter)Noddy_setfirst,
"first name", "first name",
NULL}, NULL},
{"last", {"last",
(getter)Noddy_getlast, (setter)Noddy_setlast, (getter)Noddy_getlast, (setter)Noddy_setlast,
"last name", "last name",
NULL}, NULL},
...@@ -705,7 +705,7 @@ and register it in the \member{tp_getset} slot: ...@@ -705,7 +705,7 @@ and register it in the \member{tp_getset} slot:
Noddy_getseters, /* tp_getset */ Noddy_getseters, /* tp_getset */
\end{verbatim} \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 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 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) ...@@ -737,10 +737,10 @@ Noddy_init(Noddy *self, PyObject *args, PyObject *kwds)
static char *kwlist[] = {"first", "last", "number", NULL}; static char *kwlist[] = {"first", "last", "number", NULL};
if (! PyArg_ParseTupleAndKeywords(args, kwds, "|SSi", kwlist, if (! PyArg_ParseTupleAndKeywords(args, kwds, "|SSi", kwlist,
&first, &last, &first, &last,
&self->number)) &self->number))
return -1; return -1;
if (first) { if (first) {
tmp = self->first; tmp = self->first;
...@@ -838,11 +838,11 @@ For each subobject that can participate in cycles, we need to call the ...@@ -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. \cfunction{visit()} function, which is passed to the traversal method.
The \cfunction{visit()} function takes as arguments the subobject and The \cfunction{visit()} function takes as arguments the subobject and
the extra argument \var{arg} passed to the traversal method. It 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 Python 2.4 and higher provide a \cfunction{Py_VISIT()} macro that automates
calling visit functions. With \cfunction{Py_VISIT()}, the calling visit functions. With \cfunction{Py_VISIT()},
\cfunction{Noddy_traverse()} can be simplified: \cfunction{Noddy_traverse()} can be simplified:
...@@ -856,12 +856,17 @@ Noddy_traverse(Noddy *self, visitproc visit, void *arg) ...@@ -856,12 +856,17 @@ Noddy_traverse(Noddy *self, visitproc visit, void *arg)
} }
\end{verbatim} \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 We also need to provide a method for clearing any subobjects that can
participate in cycles. We implement the method and reimplement the participate in cycles. We implement the method and reimplement the
deallocator to use it: deallocator to use it:
\begin{verbatim} \begin{verbatim}
static int static int
Noddy_clear(Noddy *self) Noddy_clear(Noddy *self)
{ {
PyObject *tmp; PyObject *tmp;
...@@ -903,7 +908,7 @@ the careful decrementing of reference counts. With ...@@ -903,7 +908,7 @@ the careful decrementing of reference counts. With
simplified: simplified:
\begin{verbatim} \begin{verbatim}
static int static int
Noddy_clear(Noddy *self) Noddy_clear(Noddy *self)
{ {
Py_CLEAR(self->first); Py_CLEAR(self->first);
...@@ -973,7 +978,7 @@ later. ...@@ -973,7 +978,7 @@ later.
Here you can put a string (or its address) that you want returned when Here you can put a string (or its address) that you want returned when
the Python script references \code{obj.__doc__} to retrieve the the Python script references \code{obj.__doc__} to retrieve the
doc string. doc string.
Now we come to the basic type methods---the ones most extension types Now we come to the basic type methods---the ones most extension types
will implement. will implement.
...@@ -1281,7 +1286,7 @@ to retrieve the descriptor from the class object, and get the ...@@ -1281,7 +1286,7 @@ to retrieve the descriptor from the class object, and get the
doc string using its \member{__doc__} attribute. doc string using its \member{__doc__} attribute.
As with the \member{tp_methods} table, a sentinel entry with a 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 % 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 ...@@ -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 third parameter will be \NULL. Here is an example that simply raises
an exception; if this were really all you wanted, the an exception; if this were really all you wanted, the
\member{tp_setattr} handler should be set to \NULL. \member{tp_setattr} handler should be set to \NULL.
\begin{verbatim} \begin{verbatim}
static int static int
newdatatype_setattr(newdatatypeobject *obj, char *name, PyObject *v) newdatatype_setattr(newdatatypeobject *obj, char *name, PyObject *v)
...@@ -1389,7 +1394,7 @@ static int ...@@ -1389,7 +1394,7 @@ static int
newdatatype_compare(newdatatypeobject * obj1, newdatatypeobject * obj2) newdatatype_compare(newdatatypeobject * obj1, newdatatypeobject * obj2)
{ {
long result; long result;
if (obj1->obj_UnderlyingDatatypePtr->size < if (obj1->obj_UnderlyingDatatypePtr->size <
obj2->obj_UnderlyingDatatypePtr->size) { obj2->obj_UnderlyingDatatypePtr->size) {
result = -1; result = -1;
...@@ -1489,7 +1494,7 @@ This function takes three arguments: ...@@ -1489,7 +1494,7 @@ This function takes three arguments:
this is non-\NULL, raise a \exception{TypeError} with a message this is non-\NULL, raise a \exception{TypeError} with a message
saying that keyword arguments are not supported. saying that keyword arguments are not supported.
\end{enumerate} \end{enumerate}
Here is a desultory example of the implementation of the call function. Here is a desultory example of the implementation of the call function.
\begin{verbatim} \begin{verbatim}
......
...@@ -302,7 +302,11 @@ PyAPI_FUNC(void) PyObject_GC_Del(void *); ...@@ -302,7 +302,11 @@ PyAPI_FUNC(void) PyObject_GC_Del(void *);
( (type *) _PyObject_GC_NewVar((typeobj), (n)) ) ( (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) \ #define Py_VISIT(op) \
do { \ do { \
if (op) { \ if (op) { \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment