为什么 PyMethodDef 数组需要一个包含多个 NULL 的标记元素?
Why does PyMethodDef arrays require a sentinel element containing multiple NULLs?
几个Python结构似乎需要一个哨兵(可能是为了知道什么时候"stop")。但是为什么有些,比如 PyMethodDef
的数组,有一个用多个 NULL
初始化的标记元素?
例如zip
:
static PyMethodDef zip_methods[] = {
{"__reduce__", (PyCFunction)zip_reduce, METH_NOARGS, reduce_doc},
{NULL, NULL} /* sentinel */
};
为什么 "sentinel array" 中的最后一个 PyMethodDef
有两个 NULL
?为什么不只是 1?或者假设 __reduce__
有 4 个条目,为什么不将 4 个 NULL
作为标记元素?
我不这么认为。有两个原因:
1) 在 Python 源代码中它只检查名称是否为 NULL。
据我所知,PyMethodDef
数组用在两个地方:将方法附加到类型时,以及将方法附加到模块时。
要找到相关的代码位,首先要注意所有类型都经过 PyType_Ready
,大多数模块都经过 PyModule_Init
,因此从那里开始搜索。 PyModule_Create
转发到 PyModule_Create2
。在 PyType_Ready
中,如果你想自己做一些低级的事情,方法由内部函数 add_methods
. In PyModule_Create2
there is all call to PyModule_AddFunctions
which is actually a public function 处理,然后调用内部函数 _add_methods_to_object
.
这两个内部函数都有一个for循环来遍历方法并将它们添加到相关字典中。在both cases中继续循环的条件是meth->ml_name!=NULL
.
因此,至少目前只检查名称。
2) In both C and C++ partial initialization guarantees that the remaining fields are zero/default initialized。因此,只需将哨兵的第一个元素初始化为 0 即可确保所有其他元素都初始化为 0。您甚至可以只使用 {}
.
(作为旁注,Python 在它定义的大型结构中经常使用这种自动零初始化,例如 PyTypeObject
,它很大,你很少费心去完整填写。)
写完这个答案我发现这个有.
所以总而言之 - Python 只检查 ml_name
(虽然这是一个实现细节,所以我想如果他们发现 NULL
名称的用途,将来可能会改变非 NULL
方法),并且 C 无论如何都会自动将哨兵归零。不知道为什么约定俗成要设置两个元素,不过按照约定还是有话要说的。
几个Python结构似乎需要一个哨兵(可能是为了知道什么时候"stop")。但是为什么有些,比如 PyMethodDef
的数组,有一个用多个 NULL
初始化的标记元素?
例如zip
:
static PyMethodDef zip_methods[] = {
{"__reduce__", (PyCFunction)zip_reduce, METH_NOARGS, reduce_doc},
{NULL, NULL} /* sentinel */
};
为什么 "sentinel array" 中的最后一个 PyMethodDef
有两个 NULL
?为什么不只是 1?或者假设 __reduce__
有 4 个条目,为什么不将 4 个 NULL
作为标记元素?
我不这么认为。有两个原因:
1) 在 Python 源代码中它只检查名称是否为 NULL。
据我所知,PyMethodDef
数组用在两个地方:将方法附加到类型时,以及将方法附加到模块时。
要找到相关的代码位,首先要注意所有类型都经过 PyType_Ready
,大多数模块都经过 PyModule_Init
,因此从那里开始搜索。 PyModule_Create
转发到 PyModule_Create2
。在 PyType_Ready
中,如果你想自己做一些低级的事情,方法由内部函数 add_methods
. In PyModule_Create2
there is all call to PyModule_AddFunctions
which is actually a public function 处理,然后调用内部函数 _add_methods_to_object
.
这两个内部函数都有一个for循环来遍历方法并将它们添加到相关字典中。在both cases中继续循环的条件是meth->ml_name!=NULL
.
因此,至少目前只检查名称。
2) In both C and C++ partial initialization guarantees that the remaining fields are zero/default initialized。因此,只需将哨兵的第一个元素初始化为 0 即可确保所有其他元素都初始化为 0。您甚至可以只使用 {}
.
(作为旁注,Python 在它定义的大型结构中经常使用这种自动零初始化,例如 PyTypeObject
,它很大,你很少费心去完整填写。)
写完这个答案我发现这个有
所以总而言之 - Python 只检查 ml_name
(虽然这是一个实现细节,所以我想如果他们发现 NULL
名称的用途,将来可能会改变非 NULL
方法),并且 C 无论如何都会自动将哨兵归零。不知道为什么约定俗成要设置两个元素,不过按照约定还是有话要说的。