Skip to content

[2.7] bpo-29165: doc: make extending/newtypes more Python 3 friendly #211

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 32 additions & 39 deletions Doc/extending/newtypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,27 +79,26 @@ Python integers::
Moving on, we come to the crunch --- the type object. ::

static PyTypeObject noddy_NoddyType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"noddy.Noddy", /*tp_name*/
sizeof(noddy_NoddyObject), /*tp_basicsize*/
0, /*tp_itemsize*/
0, /*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 */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
PyVarObject_HEAD_INIT(NULL, 0)
"noddy.Noddy", /* tp_name */
sizeof(noddy_NoddyObject), /* tp_basicsize */
0, /* tp_itemsize */
0, /* 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 */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"Noddy objects", /* tp_doc */
};

Expand All @@ -111,23 +110,16 @@ it's common practice to not specify them explicitly unless you need them.
This is so important that we're going to pick the top of it apart still
further::

PyObject_HEAD_INIT(NULL)
PyVarObject_HEAD_INIT(NULL, 0)

This line is a bit of a wart; what we'd like to write is::

PyObject_HEAD_INIT(&PyType_Type)
PyVarObject_HEAD_INIT(&PyType_Type, 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is worth to explain what 0 means here (it is a historical artifact).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want this pull request only copies from Python 3's doc.


as the type of a type object is "type", but this isn't strictly conforming C and
some compilers complain. Fortunately, this member will be filled in for us by
:c:func:`PyType_Ready`. ::

0, /* ob_size */

The :attr:`ob_size` field of the header is not used; its 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. ::

"noddy.Noddy", /* tp_name */

The name of our type. This will appear in the default textual representation of
Expand Down Expand Up @@ -171,7 +163,7 @@ for now.
Skipping a number of type methods that we don't provide, we set the class flags
to :const:`Py_TPFLAGS_DEFAULT`. ::

Py_TPFLAGS_DEFAULT, /*tp_flags*/
Py_TPFLAGS_DEFAULT, /* tp_flags */

All types should include this constant in their flags. It enables all of the
members defined by the current version of Python.
Expand Down Expand Up @@ -244,7 +236,7 @@ doesn't do anything. It can't even be subclassed.
Adding data and methods to the Basic example
--------------------------------------------

Let's expend the basic example to add some data and methods. Let's also make
Let's extend the basic example to add some data and methods. Let's also make
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"extend" or "expand"?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the type usable as a base class. We'll create a new module, :mod:`noddy2` that
adds these capabilities:

Expand Down Expand Up @@ -284,7 +276,7 @@ allocation and deallocation. At a minimum, we need a deallocation method::
{
Py_XDECREF(self->first);
Py_XDECREF(self->last);
self->ob_type->tp_free((PyObject*)self);
Py_TYPE(self)->tp_free((PyObject*)self);
}

which is assigned to the :c:member:`~PyTypeObject.tp_dealloc` member::
Expand Down Expand Up @@ -497,7 +489,7 @@ concatenation of the first and last names. ::
The method is implemented as a C function that takes a :class:`Noddy` (or
:class:`Noddy` subclass) instance as the first argument. Methods always take an
instance as the first argument. Methods often take positional and keyword
arguments as well, but in this cased we don't take any and don't need to accept
arguments as well, but in this case we don't take any and don't need to accept
a positional argument tuple or keyword argument dictionary. This method is
equivalent to the Python method::

Expand Down Expand Up @@ -806,7 +798,7 @@ decrementing of reference counts. With :c:func:`Py_CLEAR`, the

Finally, we add the :const:`Py_TPFLAGS_HAVE_GC` flag to the class flags::

Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */

That's pretty much it. If we had written custom :c:member:`~PyTypeObject.tp_alloc` or
:c:member:`~PyTypeObject.tp_free` slots, we'd need to modify them for cyclic-garbage collection.
Expand Down Expand Up @@ -965,14 +957,15 @@ Finalization and De-allocation

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::
has memory to free or other clean-up to perform, you can put it here. The
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is changed in these lines?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

object itself needs to be freed here as well. Here is an example of this
function::

static void
newdatatype_dealloc(newdatatypeobject * obj)
{
free(obj->obj_UnderlyingDatatypePtr);
obj->ob_type->tp_free(obj);
Py_TYPE(obj)->tp_free(obj);
}

.. index::
Expand Down Expand Up @@ -1015,7 +1008,7 @@ done. This can be done using the :c:func:`PyErr_Fetch` and

Py_DECREF(self->my_callback);
}
obj->ob_type->tp_free((PyObject*)self);
Py_TYPE(obj)->tp_free((PyObject*)self);
}


Expand Down
41 changes: 20 additions & 21 deletions Doc/includes/noddy.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,26 @@ typedef struct {
} noddy_NoddyObject;

static PyTypeObject noddy_NoddyType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"noddy.Noddy", /*tp_name*/
sizeof(noddy_NoddyObject), /*tp_basicsize*/
0, /*tp_itemsize*/
0, /*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 */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
PyVarObject_HEAD_INIT(NULL, 0)
"noddy.Noddy", /* tp_name */
sizeof(noddy_NoddyObject), /* tp_basicsize */
0, /* tp_itemsize */
0, /* 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 */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"Noddy objects", /* tp_doc */
};

Expand Down
80 changes: 39 additions & 41 deletions Doc/includes/noddy2.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Noddy_dealloc(Noddy* self)
{
Py_XDECREF(self->first);
Py_XDECREF(self->last);
self->ob_type->tp_free((PyObject*)self);
Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *
Expand All @@ -24,18 +24,16 @@ Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
self = (Noddy *)type->tp_alloc(type, 0);
if (self != NULL) {
self->first = PyString_FromString("");
if (self->first == NULL)
{
if (self->first == NULL) {
Py_DECREF(self);
return NULL;
}
}

self->last = PyString_FromString("");
if (self->last == NULL)
{
if (self->last == NULL) {
Py_DECREF(self);
return NULL;
}
}

self->number = 0;
}
Expand All @@ -50,10 +48,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;
Expand Down Expand Up @@ -111,7 +109,7 @@ Noddy_name(Noddy* self)

result = PyString_Format(format, args);
Py_DECREF(args);

return result;
}

Expand All @@ -123,34 +121,34 @@ static PyMethodDef Noddy_methods[] = {
};

static PyTypeObject NoddyType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"noddy.Noddy", /*tp_name*/
sizeof(Noddy), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)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 */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
PyVarObject_HEAD_INIT(NULL, 0)
"noddy.Noddy", /* tp_name */
sizeof(Noddy), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)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 */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT |
Py_TPFLAGS_BASETYPE, /* tp_flags */
"Noddy objects", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
Noddy_methods, /* tp_methods */
Noddy_members, /* tp_members */
0, /* tp_getset */
Expand All @@ -172,7 +170,7 @@ static PyMethodDef module_methods[] = {
#define PyMODINIT_FUNC void
#endif
PyMODINIT_FUNC
initnoddy2(void)
initnoddy2(void)
{
PyObject* m;

Expand All @@ -183,7 +181,7 @@ initnoddy2(void)
"Example module that creates an extension type.");

if (m == NULL)
return;
return;

Py_INCREF(&NoddyType);
PyModule_AddObject(m, "Noddy", (PyObject *)&NoddyType);
Expand Down
Loading