summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/ext/newtypes.tex179
1 files changed, 31 insertions, 148 deletions
diff --git a/Doc/ext/newtypes.tex b/Doc/ext/newtypes.tex
index 7a0d163..5371841 100644
--- a/Doc/ext/newtypes.tex
+++ b/Doc/ext/newtypes.tex
@@ -30,66 +30,7 @@ type object.
This sort of thing can only be explained by example, so here's a
minimal, but complete, module that defines a new type:
-\begin{verbatim}
-#include <Python.h>
-
-staticforward PyTypeObject noddy_NoddyType;
-
-typedef struct {
- PyObject_HEAD
-} noddy_NoddyObject;
-
-static PyObject*
-noddy_new_noddy(PyObject* self, PyObject* args)
-{
- noddy_NoddyObject* noddy;
-
- if (!PyArg_ParseTuple(args,":new_noddy"))
- return NULL;
-
- noddy = PyObject_New(noddy_NoddyObject, &noddy_NoddyType);
-
- return (PyObject*)noddy;
-}
-
-static void
-noddy_noddy_dealloc(PyObject* self)
-{
- PyObject_Del(self);
-}
-
-static PyTypeObject noddy_NoddyType = {
- PyObject_HEAD_INIT(NULL)
- 0,
- "Noddy",
- sizeof(noddy_NoddyObject),
- 0,
- noddy_noddy_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- 0, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- 0, /*tp_hash */
-};
-
-static PyMethodDef noddy_methods[] = {
- {"new_noddy", noddy_new_noddy, METH_VARARGS,
- "Create a new Noddy object."},
- {NULL, NULL, 0, NULL}
-};
-
-DL_EXPORT(void)
-initnoddy(void)
-{
- noddy_NoddyType.ob_type = &PyType_Type;
-
- Py_InitModule("noddy", noddy_methods);
-}
-\end{verbatim}
+\verbatiminput{noddy.c}
Now that's quite a bit to take in at once, but hopefully bits will
seem familiar from the last chapter.
@@ -150,9 +91,10 @@ noddy_new_noddy(PyObject* self, PyObject* args)
This is in fact just a regular module function, as described in the
last chapter. The reason it gets special mention is that this is
-where we create our Noddy object. Defining PyTypeObject structures is
-all very well, but if there's no way to actually \emph{create} one
-of the wretched things it is not going to do anyone much good.
+where we create our Noddy object. Defining \ctype{PyTypeObject}
+structures is all very well, but if there's no way to actually
+\emph{create} one of the wretched things it is not going to do anyone
+much good.
Almost always, you create objects with a call of the form:
@@ -161,11 +103,23 @@ PyObject_New(<type>, &<type object>);
\end{verbatim}
This allocates the memory and then initializes the object (sets
-the reference count to one, makes the \cdata{ob_type} pointer point at
+the reference count to one, makes the \member{ob_type} pointer point at
the right place and maybe some other stuff, depending on build options).
You \emph{can} do these steps separately if you have some reason to
--- but at this level we don't bother.
+Note that \cfunction{PyObject_New()} is a polymorphic macro rather
+than a real function. The first parameter is the name of the C
+structure that represents an object of our new type, and the return
+value is a pointer to that type. This would be
+\ctype{noddy_NoddyObject} in our example:
+
+\begin{verbatim}
+ noddy_NoddyObject *my_noddy;
+
+ my_noddy = PyObject_New(noddy_NoddyObject, &noddy_NoddyType);
+\end{verbatim}
+
We cast the return value to a \ctype{PyObject*} because that's what
the Python runtime expects. This is safe because of guarantees about
the layout of structures in the C standard, and is a fairly common C
@@ -236,14 +190,17 @@ This line is a bit of a wart; what we'd like to write is:
as the type of a type object is ``type'', but this isn't strictly
conforming C and some compilers complain. So instead we fill in the
-\cdata{ob_type} field of \cdata{noddy_NoddyType} at the earliest
+\member{ob_type} field of \cdata{noddy_NoddyType} at the earliest
oppourtunity --- in \cfunction{initnoddy()}.
\begin{verbatim}
0,
\end{verbatim}
-XXX why does the type info struct start PyObject_*VAR*_HEAD??
+The \member{ob_size} field of the header is not used; it's presence in
+the type structure is a historical artifact that is maintained for
+binary compatibility with extension modules compiled for older
+versions of Python. Always set this field to zero.
\begin{verbatim}
"Noddy",
@@ -282,8 +239,8 @@ the deallocation function.
noddy_noddy_dealloc, /*tp_dealloc*/
\end{verbatim}
-From here, all the type methods are nil so I won't go over them yet -
-that's for the next section!
+From here, all the type methods are \NULL, so I won't go over them yet
+--- that's for the next section!
Everything else in the file should be familiar, except for this line
in \cfunction{initnoddy}:
@@ -302,15 +259,15 @@ file called \file{noddymodule.c} and
\begin{verbatim}
from distutils.core import setup, Extension
-setup(name = "noddy", version = "1.0",
- ext_modules = [Extension("noddy", ["noddymodule.c"])])
+setup(name="noddy", version="1.0",
+ ext_modules=[Extension("noddy", ["noddymodule.c"])])
\end{verbatim}
in a file called \file{setup.py}; then typing
\begin{verbatim}
-$ python setup.py build%$
-\end{verbatim}
+$ python setup.py build
+\end{verbatim} %$ <-- bow to font-lock ;-(
at a shell should produce a file \file{noddy.so} in a subdirectory;
move to that directory and fire up Python --- you should be able to
@@ -328,81 +285,7 @@ you can implement and what they do.
Here is the definition of \ctype{PyTypeObject}, with some fields only
used in debug builds omitted:
-\begin{verbatim}
-typedef struct _typeobject {
- PyObject_VAR_HEAD
- char *tp_name; /* For printing */
- int tp_basicsize, tp_itemsize; /* For allocation */
-
- /* Methods to implement standard operations */
-
- destructor tp_dealloc;
- printfunc tp_print;
- getattrfunc tp_getattr;
- setattrfunc tp_setattr;
- cmpfunc tp_compare;
- reprfunc tp_repr;
-
- /* Method suites for standard classes */
-
- PyNumberMethods *tp_as_number;
- PySequenceMethods *tp_as_sequence;
- PyMappingMethods *tp_as_mapping;
-
- /* More standard operations (here for binary compatibility) */
-
- hashfunc tp_hash;
- ternaryfunc tp_call;
- reprfunc tp_str;
- getattrofunc tp_getattro;
- setattrofunc tp_setattro;
-
- /* Functions to access object as input/output buffer */
- PyBufferProcs *tp_as_buffer;
-
- /* Flags to define presence of optional/expanded features */
- long tp_flags;
-
- 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}
+\verbatiminput{typestruct.h}
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
@@ -432,7 +315,7 @@ Try to choose something that will be helpful in such a situation!
These fields tell the runtime how much memory to allocate when new
objects of this typed are created. Python has some builtin support
for variable length structures (think: strings, lists) which is where
-the \cdata{tp_itemsize} field comes in. This will be dealt with
+the \member{tp_itemsize} field comes in. This will be dealt with
later.
\begin{verbatim}