was/is 那个 "void* <unused>" 论点是为了什么,一些 __sizeof__ 方法在 CPython 中有什么?

What was/is that "void* <unused>" argument for, that some __sizeof__ methods have in CPython?

CPython 源代码中的几个 C 类型有一个 __sizeof__ 方法,因此它们可以为具有 sys.getsizeof 的实例提供大致准确的大小(以字节为单位)。

这些方法被声明为 METH_NOARG 但有些方法确实有一个 void* whatever 参数,例如 itertools.product.__sizeof__:

static PyObject *
product_sizeof(productobject *lz, void *unused)
{
    Py_ssize_t res;

    res = _PyObject_SIZE(Py_TYPE(lz));
    res += PyTuple_GET_SIZE(lz->pools) * sizeof(Py_ssize_t);
    return PyLong_FromSsize_t(res);
}

static PyMethodDef product_methods[] = {
    /* ... */
    {"__sizeof__",      (PyCFunction)product_sizeof,      METH_NOARGS,  sizeof_doc},
    {NULL,              NULL}   /* sentinel */
};

有些人有(例如1, 2), while others don't (for example: 1, 2)。当你声明一个没有参数的方法时,有一个参数似乎没有意义。

鉴于名称 "unused",它似乎曾经有过某种意义,但我不明白是什么意思。我试过使用 "git blame" 并阅读了一些相关问题,但找不到与此 "unused" 论点相关的任何内容。我还认为它可能与 sys.getsizeof 的 "default" 参数有关,但它没有传递给方法 - 方法知道给出的默认值有什么意义...

我对此很感兴趣:争论的目的是什么(以及当它变得过时时为什么不将其删除)。

根据 Martijn Pieters 的评论,我能够找出为什么这些方法有第二个参数。没有列出的那些在参数诊所文件中有一个包装函数(所以它只是 "hidden")。它不仅与 __sizeof__ 相关,而且与所有 METH_NOARG 方法相关。

METH_NOARG documentation是:

METH_NOARGS

Methods without parameters don’t need to check whether arguments are given if they are listed with the METH_NOARGS flag. They need to be of type PyCFunction. The first parameter is typically named self and will hold a reference to the module or object instance. In all cases the second parameter will be NULL.

但是 PyCFunctions 有两个参数:

PyCFunction

Type of the functions used to implement most Python callables in C. Functions of this type take two PyObject* parameters and return one such value. If the return value is NULL, an exception shall have been set. If not NULL, the return value is interpreted as the return value of the function as exposed in Python. The function must return a new reference.

(强调我的)

对应的typedef可以在methodobject中找到:

typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);

所以在 PyMethodDef 中声明的所有方法都需要(至少)两个参数,即使它们不使用第二个参数。这就是它被称为 "unused" 的原因,它对方法本身没有任何意义。

没有只接受单个参数的特定类型的函数。 PyCFunctions 始终采用两个作为其文档状态:

Type of the functions used to implement most Python callables in C. Functions of this type take two PyObject* parameters and return one such value.

METH_NOARGS 的情况并不意味着该函数只有一个参数,而是意味着第二个参数将始终是 NULL:

The first parameter is typically named self and will hold a reference to the module or object instance. In all cases the second parameter will be NULL.

你也可以直接在调用的call.c:_PyMethodDef_RawFastCallKeywords中看到这个:

case METH_NOARGS:
    // After snipping checks away
    result = (*meth) (self, NULL);

对此有很多讨论,请参阅 here, here here 其中一些。


至于只有一个参数的版本,正如 Martijn 指出的那样,这些版本使用参数诊所来隐藏它。