Several Python structures seem to need a sentinel (probably in order to know when to "stop"). But why do some, like arrays of PyMethodDef, have a sentinel element initialized with multiple NULLs?
For example zip:
static PyMethodDef zip_methods[] = {
{"__reduce__", (PyCFunction)zip_reduce, METH_NOARGS, reduce_doc},
{NULL, NULL} /* sentinel */
};
Why does the last PyMethodDef in the "sentinel array" have the two NULLs? Why not just 1? Or given that __reduce__ has 4 entries why not 4 NULLs as sentinel element?
I don't think it does. For two reasons:
1) In the Python source code it only checks the name against NULL.
As far as I'm aware, PyMethodDef arrays are used in two places: when attaching methods to a type, and when attaching methods to a module.
To find the relevant bit of code start by noting that all types go through PyType_Ready and most modules go through PyModule_Init so start the search there. PyModule_Create forwards to PyModule_Create2. In PyType_Ready the methods get dealt with by the internal function add_methods. In PyModule_Create2 there is all call to PyModule_AddFunctions which is actually a public function if you want to do low level stuff yourself and which in turn calls the internal function _add_methods_to_object.
Both of these internal functions have a for loop to loop over the methods and add them to the relevant dictionary. In both cases the condition to continue looping is meth->ml_name!=NULL.
Therefore, at least currently, only the name is checked.
2) In both C and C++ partial initialization guarantees that the remaining fields are zero/default initialized. Therefore just initializing the first element of the sentinel to 0 ensures that all the other elements are initialized to 0. You can even just use {}.
(As a side note, Python uses this automatic zero initialization a lot with the large structs it defines, for example PyTypeObject which is huge and which you rarely bother filling in completely.)
After writing this answer I found that this had already been discussed.
So in summary - Python only checks the ml_name (although that's an implementation detail so I guess could change in future if they find a use for a NULL name with a non-NULL method), and C automatically zeros the sentinel anyway. I don't know why the convention appears to be to set two elements, but there's something to be said from following convention.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With