Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does PyMethodDef arrays require a sentinel element containing multiple NULLs?

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?

like image 650
MSeifert Avatar asked Sep 20 '25 05:09

MSeifert


1 Answers

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.

like image 198
DavidW Avatar answered Sep 22 '25 01:09

DavidW