]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-125916: Adapt functools.reduce() to Argument Clinic (#125999)
authorSergey B Kirpichev <skirpichev@gmail.com>
Fri, 1 Nov 2024 20:15:39 +0000 (23:15 +0300)
committerGitHub <noreply@github.com>
Fri, 1 Nov 2024 20:15:39 +0000 (21:15 +0100)
Lib/test/test_inspect/test_inspect.py
Modules/_functoolsmodule.c
Modules/clinic/_functoolsmodule.c.h

index 2250b7e76dac01a5810cc0ba59168bbbd4b03fcf..a4430a868676e22805dfd701782edbdf7206e424 100644 (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
index da4e088e54621edbf13da9be2ddf495e888431f1..d2afe1a1bea018ba32181c89cf4a2ef518bdfe52 100644 (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.
+/*[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(PyObject *self, PyObject *args)
+_functools_reduce_impl(PyObject *module, PyObject *func, PyObject *seq,
+                       PyObject *result)
+/*[clinic end generated code: output=30d898fe1267c79d input=d233c2670cba7f66]*/
 {
-    PyObject *seq, *func, *result = NULL, *it;
+    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 */
 };
index e98984dc4d3a09a6fc6aa3f1cf1b676da306dd6b..0564921034be47b80c3a118bd276266e2080cfa6 100644 (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]*/