Extending and Embedding Python, Release 3.9.5 Chapter 2. Creating extensions without third party tools 38 4 Also, even with our attributes restricted to strings instances, the user could pass arbitrary str subclasses and therefore still create reference cycles. (continues on next page) 2.2.4 Supporting cyclic garbage collection Python has a cyclic garbage collector (GC) that can identify unneeded objects even when their reference counts are not zero. This can happen when objects are involved in cycles. For example, consider: In this example, we create a list that contains itself. When we delete it, it still has a reference from itself. Its reference count doesn’t drop to zero. Fortunately, Python’s cyclic garbage collector will eventually figure out that the list is garbage and free it. In the second version of the$_{Custom}$example, we allowed any kind of object to be stored in the$_{first}$ or$_{last}$ attributes$^{4}$. Besides, in the second and third versions, we allowed subclassing $_{Custom}$, and subclasses may add arbitrary attributes. For any of those two reasons,$_{Custom}$objects can participate in cycles: To allow a$_{Custom}$instance participating in a reference cycle to be properly detected and collected by the cyclic GC, our$_{Custom}$type needs to fill two additional slots and to enable a flag that enables these slots: >>> l =[] >>> l.append(l) >>> del l >>> import custom3 >>> classDerived (custom3 .Custom): pass ... >>> n =Derived() >>> n.some_attribute=n #define PY_SSIZE_T_CLEAN #include<Python.h> #include"structmember.h" typedef struct { PyObject_HEAD PyObject *first; /* first name */ PyObject *last; /* last name */ int number; } CustomObject; static int Custom_traverse(CustomObject *self, visitproc visit, void *arg) { Py_VISIT(self->first); Py_VISIT(self->last); return 0; } static int Custom_clear(CustomObject *self) { Py_CLEAR(self->first); Py_CLEAR(self->last); return 0; } static void Custom_dealloc(CustomObject *self) { PyObject_GC_UnTrack(self); Custom_clear(self); Py_TYPE(self) ->tp_free((PyObject *) self); }