I was reading through this tutorial in order to learn how to write C extension module to define new types. At some point the following tp_init
implementation was given:
static int
Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
{
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL, *tmp;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
&first, &last,
&self->number))
return -1;
if (first) {
tmp = self->first;
Py_INCREF(first);
self->first = first;
Py_XDECREF(tmp);
}
if (last) {
tmp = self->last;
Py_INCREF(last);
self->last = last;
Py_XDECREF(tmp);
}
return 0;
}
The trouble I'm facing is that I can't see any harm to assign the first member like this:
if (first) {
Py_XDECREF(self->first);
Py_INCREF(first);
self->first = first;
}
On the other hand, the said tutorial warn us from using it because:
Our type doesn’t restrict the type of the first member, so it could be any kind of object. It could have a destructor that causes code to be executed that tries to access the first member
It also goes on to state:
To be paranoid and protect ourselves against this possibility, we almost always reassign members before decrementing their reference counts
Taking those warnings into account, I still can't see any practical differences between the two ways. So, why should I use the first one which reassign the member first
to a new PyObject before decrementing the old PyObject reference counts?