Hi,
In my previous "Open questions about borrowed references" thread, I
asked if it's an issue or not that Py_TYPE() returns a borrowed
reference.
It seems like most people say that it's not an issue. If you want to
discuss if Py_TYPE() is an issue, please contribute to the other
thread. Here I only want to share my results. Honestly, I'm still not
100% convinced that Py_TYPE() is an issue :-)
I experimented anyway a C API without Py_TYPE(). I chose to add 3
functions/features:
* ``Py_GetType()``: similar to ``Py_TYPE()`` but returns a strong reference
* ``Py_TYPE_IS(ob, type)``: equivalent to ``Py_TYPE(ob) == type``
* ``%T`` format for ``PyUnicode_FromFormat()``
Most of the usage of Py_TYPE() are the following 5 patterns. For the
last one, I'm not sure that the "N" format of Py_BuildValue() should
stay since it's also based on borrowed reference. Replacing Py_TYPE()
requires a lot of changes, and I made many copy/paste mistakes. If we
chose to remove Py_TYPE(), we really need a tool to automate
refactoring. Otherwise, the risk of introducing a regression is just
too high and send the wrong signals to users.
Dealloc::
Py_TYPE(self)->tp_free((PyObject *)self);
becomes::
PyTypeObject *type = Py_GetType(self);
type->tp_free((PyObject *)self);
Py_DECREF(type);
Size::
res = _PyObject_SIZE(Py_TYPE(self)) + self->allocated *
self->ob_descr->itemsize;
becomes::
PyTypeObject *type = Py_GetType(self);
res = _PyObject_SIZE(type) + self->allocated * self->ob_descr->itemsize;
Py_DECREF(type);
Error::
PyErr_Format(PyExc_TypeError,
"first argument must be a type object, not %.200s",
Py_TYPE(arraytype)->tp_name);
becomes::
PyErr_Format(PyExc_TypeError,
"first argument must be a type object, not %T",
arraytype);
Py_BuildValue::
result = Py_BuildValue(
"N(CO)O", Py_GetType(self), typecode, list, dict);
becomes::
result = Py_BuildValue(
"N(CO)O", Py_GetType(self), typecode, list, dict);
Victor