@@ -250,16 +250,17 @@ Because we now have data to manage, we have to be more careful about object
250
250
allocation and deallocation. At a minimum, we need a deallocation method::
251
251
252
252
static void
253
- Custom_dealloc(CustomObject *self )
253
+ Custom_dealloc(PyObject *op )
254
254
{
255
+ CustomObject *self = (CustomObject *) op;
255
256
Py_XDECREF(self->first);
256
257
Py_XDECREF(self->last);
257
- Py_TYPE(self)->tp_free((PyObject *) self);
258
+ Py_TYPE(self)->tp_free(self);
258
259
}
259
260
260
261
which is assigned to the :c:member: `~PyTypeObject.tp_dealloc ` member::
261
262
262
- .tp_dealloc = (destructor) Custom_dealloc,
263
+ .tp_dealloc = Custom_dealloc,
263
264
264
265
This method first clears the reference counts of the two Python attributes.
265
266
:c:func: `Py_XDECREF ` correctly handles the case where its argument is
@@ -270,11 +271,31 @@ the object's type might not be :class:`!CustomType`, because the object may
270
271
be an instance of a subclass.
271
272
272
273
.. 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
+
275
+ The explicit cast to ``CustomObject * `` above is needed because we defined
276
+ ``Custom_dealloc `` to take a ``PyObject * `` argument, as the ``tp_dealloc ``
277
+ function pointer expects to receive a ``PyObject * `` argument.
278
+ By assigning to the the ``tp_dealloc `` slot of a type, we declare
279
+ that it can only be called with instances of our ``CustomObject ``
280
+ class, so the cast to ``(CustomObject *) `` is safe.
281
+ This is object-oriented polymorphism, in C!
282
+
283
+ In existing code, or in previous versions of this tutorial,
284
+ you might see similar functions take a pointer to the subtype
285
+ object structure (``CustomObject* ``) directly, like this::
286
+
287
+ Custom_dealloc(CustomObject *self)
288
+ {
289
+ Py_XDECREF(self->first);
290
+ Py_XDECREF(self->last);
291
+ Py_TYPE(self)->tp_free((PyObject *) self);
292
+ }
293
+ ...
294
+ .tp_dealloc = (destructor) Custom_dealloc,
295
+
296
+ This does the same thing on all architectures that CPython
297
+ supports, but according to the C standard, it invokes
298
+ undefined behavior.
278
299
279
300
We want to make sure that the first and last names are initialized to empty
280
301
strings, so we provide a ``tp_new `` implementation::
@@ -352,8 +373,9 @@ We also define an initialization function which accepts arguments to provide
352
373
initial values for our instance::
353
374
354
375
static int
355
- Custom_init(CustomObject *self , PyObject *args, PyObject *kwds)
376
+ Custom_init(PyObject *op , PyObject *args, PyObject *kwds)
356
377
{
378
+ CustomObject *self = (CustomObject *) op;
357
379
static char *kwlist[] = {"first", "last", "number", NULL};
358
380
PyObject *first = NULL, *last = NULL, *tmp;
359
381
@@ -379,7 +401,7 @@ initial values for our instance::
379
401
380
402
by filling the :c:member: `~PyTypeObject.tp_init ` slot. ::
381
403
382
- .tp_init = (initproc) Custom_init,
404
+ .tp_init = Custom_init,
383
405
384
406
The :c:member: `~PyTypeObject.tp_init ` slot is exposed in Python as the
385
407
:meth: `~object.__init__ ` method. It is used to initialize an object after it's
@@ -451,8 +473,9 @@ We define a single method, :meth:`!Custom.name`, that outputs the objects name a
451
473
concatenation of the first and last names. ::
452
474
453
475
static PyObject *
454
- Custom_name(CustomObject *self , PyObject *Py_UNUSED(ignored ))
476
+ Custom_name(PyObject *op , PyObject *Py_UNUSED(dummy ))
455
477
{
478
+ CustomObject *self = (CustomObject *) op;
456
479
if (self->first == NULL) {
457
480
PyErr_SetString(PyExc_AttributeError, "first");
458
481
return NULL;
@@ -486,7 +509,7 @@ Now that we've defined the method, we need to create an array of method
486
509
definitions::
487
510
488
511
static PyMethodDef Custom_methods[] = {
489
- {"name", (PyCFunction) Custom_name, METH_NOARGS,
512
+ {"name", Custom_name, METH_NOARGS,
490
513
"Return the name, combining the first and last name"
491
514
},
492
515
{NULL} /* Sentinel */
@@ -543,15 +566,17 @@ we'll use custom getter and setter functions. Here are the functions for
543
566
getting and setting the :attr: `!first ` attribute::
544
567
545
568
static PyObject *
546
- Custom_getfirst(CustomObject *self , void *closure)
569
+ Custom_getfirst(PyObject *op , void *closure)
547
570
{
571
+ CustomObject *self = (CustomObject *) op;
548
572
Py_INCREF(self->first);
549
573
return self->first;
550
574
}
551
575
552
576
static int
553
- Custom_setfirst(CustomObject *self , PyObject *value, void *closure)
577
+ Custom_setfirst(PyObject *op , PyObject *value, void *closure)
554
578
{
579
+ CustomObject *self = (CustomObject *) op;
555
580
PyObject *tmp;
556
581
if (value == NULL) {
557
582
PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
@@ -583,9 +608,9 @@ new value is not a string.
583
608
We create an array of :c:type: `PyGetSetDef ` structures::
584
609
585
610
static PyGetSetDef Custom_getsetters[] = {
586
- {"first", (getter) Custom_getfirst, (setter) Custom_setfirst,
611
+ {"first", Custom_getfirst, Custom_setfirst,
587
612
"first name", NULL},
588
- {"last", (getter) Custom_getlast, (setter) Custom_setlast,
613
+ {"last", Custom_getlast, Custom_setlast,
589
614
"last name", NULL},
590
615
{NULL} /* Sentinel */
591
616
};
@@ -609,8 +634,9 @@ We also need to update the :c:member:`~PyTypeObject.tp_init` handler to only
609
634
allow strings [# ]_ to be passed::
610
635
611
636
static int
612
- Custom_init(CustomObject *self , PyObject *args, PyObject *kwds)
637
+ Custom_init(PyObject *op , PyObject *args, PyObject *kwds)
613
638
{
639
+ CustomObject *self = (CustomObject *) op;
614
640
static char *kwlist[] = {"first", "last", "number", NULL};
615
641
PyObject *first = NULL, *last = NULL, *tmp;
616
642
@@ -689,8 +715,9 @@ First, the traversal method lets the cyclic GC know about subobjects that could
689
715
participate in cycles::
690
716
691
717
static int
692
- Custom_traverse(CustomObject *self , visitproc visit, void *arg)
718
+ Custom_traverse(PyObject *op , visitproc visit, void *arg)
693
719
{
720
+ CustomObject *self = (CustomObject *) op;
694
721
int vret;
695
722
if (self->first) {
696
723
vret = visit(self->first, arg);
@@ -716,8 +743,9 @@ functions. With :c:func:`Py_VISIT`, we can minimize the amount of boilerplate
716
743
in ``Custom_traverse ``::
717
744
718
745
static int
719
- Custom_traverse(CustomObject *self , visitproc visit, void *arg)
746
+ Custom_traverse(PyObject *op , visitproc visit, void *arg)
720
747
{
748
+ CustomObject *self = (CustomObject *) op;
721
749
Py_VISIT(self->first);
722
750
Py_VISIT(self->last);
723
751
return 0;
@@ -731,8 +759,9 @@ Second, we need to provide a method for clearing any subobjects that can
731
759
participate in cycles::
732
760
733
761
static int
734
- Custom_clear(CustomObject *self )
762
+ Custom_clear(PyObject *op )
735
763
{
764
+ CustomObject *self = (CustomObject *) op;
736
765
Py_CLEAR(self->first);
737
766
Py_CLEAR(self->last);
738
767
return 0;
@@ -765,11 +794,11 @@ Here is our reimplemented deallocator using :c:func:`PyObject_GC_UnTrack`
765
794
and ``Custom_clear ``::
766
795
767
796
static void
768
- Custom_dealloc(CustomObject *self )
797
+ Custom_dealloc(PyObject *op )
769
798
{
770
- PyObject_GC_UnTrack(self );
771
- Custom_clear(self );
772
- Py_TYPE(self )->tp_free((PyObject *) self );
799
+ PyObject_GC_UnTrack(op );
800
+ (void) Custom_clear(op );
801
+ Py_TYPE(op )->tp_free(op );
773
802
}
774
803
775
804
Finally, we add the :c:macro: `Py_TPFLAGS_HAVE_GC ` flag to the class flags::
@@ -825,9 +854,10 @@ When a Python object is a :class:`!SubList` instance, its ``PyObject *`` pointer
825
854
can be safely cast to both ``PyListObject * `` and ``SubListObject * ``::
826
855
827
856
static int
828
- SubList_init(SubListObject *self , PyObject *args, PyObject *kwds)
857
+ SubList_init(PyObject *op , PyObject *args, PyObject *kwds)
829
858
{
830
- if (PyList_Type.tp_init((PyObject *) self, args, kwds) < 0)
859
+ SubListObject *self = (SubListObject *) op;
860
+ if (PyList_Type.tp_init(op, args, kwds) < 0)
831
861
return -1;
832
862
self->state = 0;
833
863
return 0;
0 commit comments