1414 This module roughly corresponds to::
1515
1616 class Xxo:
17- """A class that explicitly stores attributes in an internal dict"""
17+ """A class that explicitly stores attributes in an internal dict
18+ (to simulate custom attribute handling).
19+ """
1820
1921 def __init__(self):
2022 # In the C class, "_x_attr" is not accessible from Python code
@@ -85,13 +87,16 @@ typedef struct {
8587// Instance state
8688typedef struct {
8789 PyObject_HEAD
88- PyObject * x_attr ; /* Attributes dictionary */
90+ PyObject * x_attr ; /* Attributes dictionary.
91+ * May be NULL, which acts as an
92+ * empty dict.
93+ */
8994 char x_buffer [BUFSIZE ]; /* buffer for Py_buffer */
9095 Py_ssize_t x_exports ; /* how many buffer are exported */
9196} XxoObject ;
9297
9398#define XxoObject_CAST (op ) ((XxoObject *)(op))
94- // XXX: no good way to do this yet
99+ // TODO: full support for type-checking was added in 3.14 (Py_tp_token)
95100// #define XxoObject_Check(v) Py_IS_TYPE(v, Xxo_Type)
96101
97102static XxoObject *
@@ -112,8 +117,13 @@ newXxoObject(PyObject *module)
112117 return self ;
113118}
114119
115- /* Xxo finalization */
120+ /* Xxo finalization.
121+ *
122+ * Types that store references to other PyObjects generally need to implement
123+ * the GC slots: traverse, clear, dealloc, and (optionally) finalize.
124+ */
116125
126+ // traverse: Visit all references from an object, including its type
117127static int
118128Xxo_traverse (PyObject * op , visitproc visit , void * arg )
119129{
@@ -126,6 +136,7 @@ Xxo_traverse(PyObject *op, visitproc visit, void *arg)
126136 return 0 ;
127137}
128138
139+ // clear: drop references in order to break all reference cycles
129140static int
130141Xxo_clear (PyObject * op )
131142{
@@ -134,13 +145,16 @@ Xxo_clear(PyObject *op)
134145 return 0 ;
135146}
136147
148+ // finalize: like clear, but should leave the object in a consistent state.
149+ // Equivalent to `__del__` in Python.
137150static void
138151Xxo_finalize (PyObject * op )
139152{
140153 XxoObject * self = XxoObject_CAST (op );
141154 Py_CLEAR (self -> x_attr );
142155}
143156
157+ // dealloc: drop all remaining references and free memory
144158static void
145159Xxo_dealloc (PyObject * self )
146160{
@@ -155,6 +169,7 @@ Xxo_dealloc(PyObject *self)
155169
156170/* Xxo attribute handling */
157171
172+ // Get an attribute.
158173static PyObject *
159174Xxo_getattro (PyObject * op , PyObject * name )
160175{
@@ -168,9 +183,12 @@ Xxo_getattro(PyObject *op, PyObject *name)
168183 return NULL ;
169184 }
170185 }
186+ // Fall back to generic implementation (this handles special attributes,
187+ // raising AttributeError, etc.)
171188 return PyObject_GenericGetAttr (op , name );
172189}
173190
191+ // Set or delete an attribute.
174192static int
175193Xxo_setattro (PyObject * op , PyObject * name , PyObject * v )
176194{
@@ -198,7 +216,9 @@ Xxo_setattro(PyObject *op, PyObject *name, PyObject *v)
198216 }
199217}
200218
201- /* Xxo methods */
219+ /* Xxo methods: C functions plus a PyMethodDef array that lists them and
220+ * specifies metadata.
221+ */
202222
203223static PyObject *
204224Xxo_demo (PyObject * op , PyTypeObject * defining_class ,
@@ -234,7 +254,10 @@ static PyMethodDef Xxo_methods[] = {
234254 {NULL , NULL } /* sentinel */
235255};
236256
237- /* Xxo buffer interface */
257+ /* Xxo buffer interface: C functions later referenced from PyType_Slot array.
258+ * Other interfaces (e.g. for sequence-like or number-like types) are defined
259+ * similarly.
260+ */
238261
239262static int
240263Xxo_getbuffer (PyObject * op , Py_buffer * view , int flags )
@@ -300,6 +323,7 @@ static PyType_Spec Xxo_Type_spec = {
300323/* Str type definition*/
301324
302325static PyType_Slot Str_Type_slots [] = {
326+ // slots array intentionally kept empty
303327 {0 , 0 }, /* sentinel */
304328};
305329
@@ -400,12 +424,32 @@ xx_modexec(PyObject *m)
400424}
401425
402426static PyModuleDef_Slot xx_slots [] = {
427+
428+ /* exec function to initialize the module (called as part of import
429+ * after the object was added to sys.modules)
430+ */
403431 {Py_mod_exec , xx_modexec },
432+
433+ /* Signal that this module supports being loaded in multiple interpreters
434+ * with separate GILs (global interpreter locks).
435+ * See "Isolating Extension Modules" on how to prepare a module for this:
436+ * https://docs.python.org/3/howto/isolating-extensions.html
437+ */
404438 {Py_mod_multiple_interpreters , Py_MOD_PER_INTERPRETER_GIL_SUPPORTED },
439+
440+ /* Signal that this module does not rely on the GIL for its own needs.
441+ * Without this slot, free-threaded builds of CPython will enable
442+ * the GIL when this module is loaded.
443+ */
405444 {Py_mod_gil , Py_MOD_GIL_NOT_USED },
445+
406446 {0 , NULL }
407447};
408448
449+ // Module finalization: modules that hold references in their module state
450+ // need to implement the fullowing GC hooks. They're similar to the ones for
451+ // types (see "Xxo finalization").
452+
409453static int
410454xx_traverse (PyObject * module , visitproc visit , void * arg )
411455{
@@ -444,7 +488,9 @@ static struct PyModuleDef xxmodule = {
444488};
445489
446490
447- /* Export function for the module (*must* be called PyInit_xx) */
491+ /* Export function for the module. *Must* be called PyInit_xx; usually it is
492+ * the only non-`static` object in a module definition.
493+ */
448494
449495PyMODINIT_FUNC
450496PyInit_xxlimited (void )
0 commit comments