Python’s support for detecting and collecting garbage which involves circular references requires support from object types which are “containers” for other objects which may also be containers. Types which do not store references to other objects, or which only store references to atomic types (such as numbers or strings), do not need to provide any explicit support for garbage collection.
To create a container type, the tp_flags
field of the type object must
include the Py_TPFLAGS_HAVE_GC
and provide an implementation of the
tp_traverse
handler. If instances of the type are mutable, a
tp_clear
implementation must also be provided.
Py_TPFLAGS_HAVE_GC
Constructors for container types must conform to two rules:
PyObject_GC_New()
or PyObject_GC_NewVar()
.PyObject_GC_Track()
.PyObject_GC_New
(TYPE, PyTypeObject *type)PyObject_New()
but for container objects with the Py_TPFLAGS_HAVE_GC
flag set.PyObject_GC_NewVar
(TYPE, PyTypeObject *type, Py_ssize_t size)PyObject_NewVar()
but for container objects with the Py_TPFLAGS_HAVE_GC
flag set.PyObject_GC_Resize
(TYPE, PyVarObject *op, Py_ssize_t newsize)PyObject_NewVar()
. Returns the resized object or NULL
on failure. op must not be tracked by the collector yet.PyObject_GC_Track
(PyObject *op)tp_traverse
handler become valid, usually near the end of the constructor.PyObject_IS_GC
(PyObject *obj)Returns non-zero if the object implements the garbage collector protocol, otherwise returns 0.
The object cannot be tracked by the garbage collector if this function returns 0.
PyObject_GC_IsTracked
(PyObject *op)Returns 1 if the object type of op implements the GC protocol and op is being currently tracked by the garbage collector and 0 otherwise.
This is analogous to the Python function gc.is_tracked()
.
New in version 3.9.
PyObject_GC_IsFinalized
(PyObject *op)Returns 1 if the object type of op implements the GC protocol and op has been already finalized by the garbage collector and 0 otherwise.
This is analogous to the Python function gc.is_finalized()
.
New in version 3.9.
Similarly, the deallocator for the object must conform to a similar pair of rules:
PyObject_GC_UnTrack()
must be called.PyObject_GC_Del()
.PyObject_GC_Del
(void *op)PyObject_GC_New()
or PyObject_GC_NewVar()
.PyObject_GC_UnTrack
(void *op)PyObject_GC_Track()
can be called again on this object to add it back to the set of tracked objects. The deallocator (tp_dealloc
handler) should call this for the object before any of the fields used by the tp_traverse
handler become invalid.Changed in version 3.8: The _PyObject_GC_TRACK()
and _PyObject_GC_UNTRACK()
macros
have been removed from the public C API.
The tp_traverse
handler accepts a function parameter of this type:
(*visitproc)
(PyObject *object, void *arg)tp_traverse
handler. The function should be called with an object to traverse as object and the third parameter to the tp_traverse
handler as arg. The Python core uses several visitor functions to implement cyclic garbage detection; it’s not expected that users will need to write their own visitor functions.The tp_traverse
handler must have the following type:
(*traverseproc)
(PyObject *self, visitproc visit, void *arg)NULL
object argument. If visit returns a non-zero value that value should be returned immediately.To simplify writing tp_traverse
handlers, a Py_VISIT()
macro is
provided. In order to use this macro, the tp_traverse
implementation
must name its arguments exactly visit and arg:
Py_VISIT
(PyObject *o)If o is not NULL
, call the visit callback, with arguments o
and arg. If visit returns a non-zero value, then return it.
Using this macro, tp_traverse
handlers
look like:
static int
my_traverse(Noddy *self, visitproc visit, void *arg)
{
Py_VISIT(self->foo);
Py_VISIT(self->bar);
return 0;
}
The tp_clear
handler must be of the inquiry
type, or NULL
if the object is immutable.
(*inquiry)
(PyObject *self)Py_DECREF()
on a reference). The collector will call this method if it detects that this object is involved in a reference cycle.