Several C types in the CPython source have a __sizeof__
method so they can present approximately accurate sizes (in bytes) for instances with sys.getsizeof
.
These methods are declared METH_NOARG
but some do have a void* whatever
argument, for example 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 */
};
Some have it (e.g. 1, 2), while others don't (for example: 1, 2). It doesn't seem to make sense to have an argument when you declare it a method without arguments.
Given the name "unused" it seems like it probably had some meaning once but I can't figure out for what. I've tried using "git blame" and reading through some of the related issues but couldn't find anything with respect to this "unused" argument. I also thought it may be related to the "default" argument for sys.getsizeof
but that's not passed through to the method - and what would be the point for the method to know what default was given...
I'm interested it: What was the purpose of the argument (and when it became obsolete why wasn't it removed).
There's no specific type of function that only takes a single parameter. PyCFunction
s always take two as its documentation states:
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.
The METH_NOARGS
case doesn't mean that the function will only have a single parameter, rather, it means that the second parameter will always be 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
.
you can also see this directly in call.c:_PyMethodDef_RawFastCallKeywords
where the call is made:
case METH_NOARGS:
// After snipping checks away
result = (*meth) (self, NULL);
There's a number of discussions covering this, see here, here and here for some of these.
As for the versions that only have a single argument, as Martijn points out, these use argument clinic to hide that.