为什么 PyMethodDef 数组需要一个包含多个 NULL 的哨兵元素?



几个Python结构似乎需要一个哨兵(可能是为了知道什么时候"停止")。但是为什么有些,比如PyMethodDef数组,有一个用多个NULL初始化的哨兵元素呢?

例如zip

static PyMethodDef zip_methods[] = {
{"__reduce__",   (PyCFunction)zip_reduce,   METH_NOARGS, reduce_doc},
{NULL,           NULL}           /* sentinel */
};

为什么"哨兵阵列"中的最后一个PyMethodDef有两个NULL?为什么不只是 1?或者考虑到__reduce__有 4 个条目,为什么不 4 个NULLs 作为哨兵元素?

我认为并非如此。原因有二:

1)在Python源代码中,它只检查名称与NULL。

据我所知,PyMethodDef数组在两个地方使用:将方法附加到类型时,以及将方法附加到模块时。

要查找相关的代码位,首先要注意所有类型都经过PyType_Ready并且大多数模块都经过PyModule_Init因此请从那里开始搜索。PyModule_Create转发到PyModule_Create2.PyType_Ready方法由内部函数add_methods处理。在PyModule_Create2中,PyModule_AddFunctions如果你想自己做低级的事情,它实际上是一个公共函数,这实际上是一个公共函数,而它又调用内部函数_add_methods_to_object

这两个内部函数都有一个 for 循环来循环方法并将它们添加到相关的字典中。在这两种情况下,继续循环的条件都是meth->ml_name!=NULL

因此,至少目前只检查名称。

2) 在 C 和 C++ 中,部分初始化保证其余字段为零/默认初始化。因此,只需将哨兵的第一个元素初始化为 0 即可确保所有其他元素都初始化为 0。您甚至可以只使用{}.

(作为旁注,Python 在它定义的大结构中经常使用这种自动零初始化,例如PyTypeObject它很大,你很少费心完全填写。

写完这个答案后,我发现这已经讨论过了。


所以总而言之 - Python 只检查ml_name(尽管这是一个实现细节,所以我想如果他们发现使用非NULL方法使用NULL名称,将来可能会改变),并且 C 会自动将哨兵归零无论如何。我不知道为什么公约似乎是设定两个要素,但遵循惯例有一些话要说。

相关内容

最新更新