@@ -250,16 +250,17 @@ Because we now have data to manage, we have to be more careful about object
250250allocation and deallocation. At a minimum, we need a deallocation method::
251251
252252 static void
253- Custom_dealloc(CustomObject *self )
253+ Custom_dealloc(PyObject *op )
254254 {
255+ CustomObject *self = (CustomObject *) op;
255256 Py_XDECREF(self->first);
256257 Py_XDECREF(self->last);
257- Py_TYPE(self)->tp_free((PyObject *) self );
258+ Py_TYPE(self)->tp_free(op );
258259 }
259260
260261which is assigned to the :c:member: `~PyTypeObject.tp_dealloc ` member::
261262
262- .tp_dealloc = (destructor) Custom_dealloc,
263+ .tp_dealloc = Custom_dealloc,
263264
264265This method first clears the reference counts of the two Python attributes.
265266:c:func: `Py_XDECREF ` correctly handles the case where its argument is
@@ -270,11 +271,10 @@ the object's type might not be :class:`!CustomType`, because the object may
270271be an instance of a subclass.
271272
272273.. note ::
273- The explicit cast to ``destructor `` above is needed because we defined
274- ``Custom_dealloc `` to take a ``CustomObject * `` argument, but the ``tp_dealloc ``
275- function pointer expects to receive a ``PyObject * `` argument. Otherwise,
276- the compiler will emit a warning. This is object-oriented polymorphism,
277- in C!
274+ The explicit cast to ``CustomObject * `` above is needed because we defined
275+ ``Custom_dealloc `` to take a ``PyObject * `` argument, as the ``tp_dealloc ``
276+ function pointer expects to receive a ``PyObject * `` argument. Otherwise,
277+ this would result in an undefined behaviour at runtime!
278278
279279We want to make sure that the first and last names are initialized to empty
280280strings, so we provide a ``tp_new `` implementation::
@@ -352,8 +352,9 @@ We also define an initialization function which accepts arguments to provide
352352initial values for our instance::
353353
354354 static int
355- Custom_init(CustomObject *self , PyObject *args, PyObject *kwds)
355+ Custom_init(PyObject *op , PyObject *args, PyObject *kwds)
356356 {
357+ CustomObject *self = (CustomObject *) op;
357358 static char *kwlist[] = {"first", "last", "number", NULL};
358359 PyObject *first = NULL, *last = NULL, *tmp;
359360
@@ -379,7 +380,7 @@ initial values for our instance::
379380
380381by filling the :c:member: `~PyTypeObject.tp_init ` slot. ::
381382
382- .tp_init = (initproc) Custom_init,
383+ .tp_init = Custom_init,
383384
384385The :c:member: `~PyTypeObject.tp_init ` slot is exposed in Python as the
385386:meth: `~object.__init__ ` method. It is used to initialize an object after it's
@@ -451,8 +452,9 @@ We define a single method, :meth:`!Custom.name`, that outputs the objects name a
451452concatenation of the first and last names. ::
452453
453454 static PyObject *
454- Custom_name(CustomObject *self , PyObject *Py_UNUSED(ignored ))
455+ Custom_name(PyObject *op , PyObject *Py_UNUSED(dummy ))
455456 {
457+ CustomObject *self = (CustomObject *) op;
456458 if (self->first == NULL) {
457459 PyErr_SetString(PyExc_AttributeError, "first");
458460 return NULL;
@@ -486,7 +488,7 @@ Now that we've defined the method, we need to create an array of method
486488definitions::
487489
488490 static PyMethodDef Custom_methods[] = {
489- {"name", (PyCFunction) Custom_name, METH_NOARGS,
491+ {"name", Custom_name, METH_NOARGS,
490492 "Return the name, combining the first and last name"
491493 },
492494 {NULL} /* Sentinel */
@@ -543,15 +545,17 @@ we'll use custom getter and setter functions. Here are the functions for
543545getting and setting the :attr: `!first ` attribute::
544546
545547 static PyObject *
546- Custom_getfirst(CustomObject *self , void *closure)
548+ Custom_getfirst(PyObject *op , void *closure)
547549 {
550+ CustomObject *self = (CustomObject *) op;
548551 Py_INCREF(self->first);
549552 return self->first;
550553 }
551554
552555 static int
553- Custom_setfirst(CustomObject *self , PyObject *value, void *closure)
556+ Custom_setfirst(PyObject *op , PyObject *value, void *closure)
554557 {
558+ CustomObject *self = (CustomObject *) op;
555559 PyObject *tmp;
556560 if (value == NULL) {
557561 PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
@@ -583,9 +587,9 @@ new value is not a string.
583587We create an array of :c:type: `PyGetSetDef ` structures::
584588
585589 static PyGetSetDef Custom_getsetters[] = {
586- {"first", (getter) Custom_getfirst, (setter) Custom_setfirst,
590+ {"first", Custom_getfirst, Custom_setfirst,
587591 "first name", NULL},
588- {"last", (getter) Custom_getlast, (setter) Custom_setlast,
592+ {"last", Custom_getlast, Custom_setlast,
589593 "last name", NULL},
590594 {NULL} /* Sentinel */
591595 };
@@ -609,8 +613,9 @@ We also need to update the :c:member:`~PyTypeObject.tp_init` handler to only
609613allow strings [# ]_ to be passed::
610614
611615 static int
612- Custom_init(CustomObject *self , PyObject *args, PyObject *kwds)
616+ Custom_init(PyObject *op , PyObject *args, PyObject *kwds)
613617 {
618+ CustomObject *self = (CustomObject *) op;
614619 static char *kwlist[] = {"first", "last", "number", NULL};
615620 PyObject *first = NULL, *last = NULL, *tmp;
616621
@@ -689,8 +694,9 @@ First, the traversal method lets the cyclic GC know about subobjects that could
689694participate in cycles::
690695
691696 static int
692- Custom_traverse(CustomObject *self , visitproc visit, void *arg)
697+ Custom_traverse(PyObject *op , visitproc visit, void *arg)
693698 {
699+ CustomObject *self = (CustomObject *) op;
694700 int vret;
695701 if (self->first) {
696702 vret = visit(self->first, arg);
@@ -716,8 +722,9 @@ functions. With :c:func:`Py_VISIT`, we can minimize the amount of boilerplate
716722in ``Custom_traverse ``::
717723
718724 static int
719- Custom_traverse(CustomObject *self , visitproc visit, void *arg)
725+ Custom_traverse(PyObject *op , visitproc visit, void *arg)
720726 {
727+ CustomObject *self = (CustomObject *) op;
721728 Py_VISIT(self->first);
722729 Py_VISIT(self->last);
723730 return 0;
@@ -731,8 +738,9 @@ Second, we need to provide a method for clearing any subobjects that can
731738participate in cycles::
732739
733740 static int
734- Custom_clear(CustomObject *self )
741+ Custom_clear(PyObject *op )
735742 {
743+ CustomObject *self = (CustomObject *) op;
736744 Py_CLEAR(self->first);
737745 Py_CLEAR(self->last);
738746 return 0;
@@ -765,11 +773,11 @@ Here is our reimplemented deallocator using :c:func:`PyObject_GC_UnTrack`
765773and ``Custom_clear ``::
766774
767775 static void
768- Custom_dealloc(CustomObject *self )
776+ Custom_dealloc(PyObject *op )
769777 {
770- PyObject_GC_UnTrack(self );
771- Custom_clear(self );
772- Py_TYPE(self )->tp_free((PyObject *) self );
778+ PyObject_GC_UnTrack(op );
779+ (void) Custom_clear(op );
780+ Py_TYPE(op )->tp_free(op );
773781 }
774782
775783Finally, we add the :c:macro: `Py_TPFLAGS_HAVE_GC ` flag to the class flags::
@@ -825,9 +833,10 @@ When a Python object is a :class:`!SubList` instance, its ``PyObject *`` pointer
825833can be safely cast to both ``PyListObject * `` and ``SubListObject * ``::
826834
827835 static int
828- SubList_init(SubListObject *self , PyObject *args, PyObject *kwds)
836+ SubList_init(PyObject *op , PyObject *args, PyObject *kwds)
829837 {
830- if (PyList_Type.tp_init((PyObject *) self, args, kwds) < 0)
838+ SubListObject *self = (SubListObject *) op;
839+ if (PyList_Type.tp_init(op, args, kwds) < 0)
831840 return -1;
832841 self->state = 0;
833842 return 0;
0 commit comments