gh-125916: Adapt functools.reduce() to Argument Clinic (#125999)

This commit is contained in:
Sergey B Kirpichev 2024-11-01 23:15:39 +03:00 committed by GitHub
parent 74cf5967f3
commit 51ef54abc4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 72 additions and 24 deletions

View File

@ -5708,8 +5708,8 @@ class TestSignatureDefinitions(unittest.TestCase):
self._test_module_has_signatures(faulthandler, unsupported_signature=unsupported_signature)
def test_functools_module_has_signatures(self):
no_signature = {'reduce'}
self._test_module_has_signatures(functools, no_signature)
unsupported_signature = {"reduce"}
self._test_module_has_signatures(functools, unsupported_signature=unsupported_signature)
def test_gc_module_has_signatures(self):
import gc

View File

@ -932,15 +932,31 @@ _functools_cmp_to_key_impl(PyObject *module, PyObject *mycmp)
/* reduce (used to be a builtin) ********************************************/
// Not converted to argument clinic, because of `args` in-place modification.
// AC will affect performance.
static PyObject *
functools_reduce(PyObject *self, PyObject *args)
{
PyObject *seq, *func, *result = NULL, *it;
/*[clinic input]
_functools.reduce
function as func: object
iterable as seq: object
initial as result: object = NULL
/
Apply a function of two arguments cumulatively to the items of an iterable, from left to right.
This effectively reduces the iterable to a single value. If initial is present,
it is placed before the items of the iterable in the calculation, and serves as
a default when the iterable is empty.
For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
calculates ((((1 + 2) + 3) + 4) + 5).
[clinic start generated code]*/
static PyObject *
_functools_reduce_impl(PyObject *module, PyObject *func, PyObject *seq,
PyObject *result)
/*[clinic end generated code: output=30d898fe1267c79d input=d233c2670cba7f66]*/
{
PyObject *args, *it;
if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result))
return NULL;
if (result != NULL)
Py_INCREF(result);
@ -1006,18 +1022,6 @@ Fail:
return NULL;
}
PyDoc_STRVAR(functools_reduce_doc,
"reduce(function, iterable[, initial], /) -> value\n\
\n\
Apply a function of two arguments cumulatively to the items of an iterable, from left to right.\n\
\n\
This effectively reduces the iterable to a single value. If initial is present,\n\
it is placed before the items of the iterable in the calculation, and serves as\n\
a default when the iterable is empty.\n\
\n\
For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])\n\
calculates ((((1 + 2) + 3) + 4) + 5).");
/* lru_cache object **********************************************************/
/* There are four principal algorithmic differences from the pure python version:
@ -1722,7 +1726,7 @@ PyDoc_STRVAR(_functools_doc,
"Tools that operate on functions.");
static PyMethodDef _functools_methods[] = {
{"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc},
_FUNCTOOLS_REDUCE_METHODDEF
_FUNCTOOLS_CMP_TO_KEY_METHODDEF
{NULL, NULL} /* sentinel */
};

View File

@ -67,6 +67,50 @@ exit:
return return_value;
}
PyDoc_STRVAR(_functools_reduce__doc__,
"reduce($module, function, iterable, initial=<unrepresentable>, /)\n"
"--\n"
"\n"
"Apply a function of two arguments cumulatively to the items of an iterable, from left to right.\n"
"\n"
"This effectively reduces the iterable to a single value. If initial is present,\n"
"it is placed before the items of the iterable in the calculation, and serves as\n"
"a default when the iterable is empty.\n"
"\n"
"For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])\n"
"calculates ((((1 + 2) + 3) + 4) + 5).");
#define _FUNCTOOLS_REDUCE_METHODDEF \
{"reduce", _PyCFunction_CAST(_functools_reduce), METH_FASTCALL, _functools_reduce__doc__},
static PyObject *
_functools_reduce_impl(PyObject *module, PyObject *func, PyObject *seq,
PyObject *result);
static PyObject *
_functools_reduce(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
{
PyObject *return_value = NULL;
PyObject *func;
PyObject *seq;
PyObject *result = NULL;
if (!_PyArg_CheckPositional("reduce", nargs, 2, 3)) {
goto exit;
}
func = args[0];
seq = args[1];
if (nargs < 3) {
goto skip_optional;
}
result = args[2];
skip_optional:
return_value = _functools_reduce_impl(module, func, seq, result);
exit:
return return_value;
}
PyDoc_STRVAR(_functools__lru_cache_wrapper_cache_info__doc__,
"cache_info($self, /)\n"
"--\n"
@ -114,4 +158,4 @@ _functools__lru_cache_wrapper_cache_clear(PyObject *self, PyObject *Py_UNUSED(ig
return return_value;
}
/*[clinic end generated code: output=755265bb6d5ea751 input=a9049054013a1b77]*/
/*[clinic end generated code: output=214d6c6307cfcd91 input=a9049054013a1b77]*/