mirror of
https://github.com/python/cpython.git
synced 2025-09-27 10:50:04 +00:00
bpo-44019: Implement operator.call(). (GH-27888)
Having `operator.call(obj, arg)` mean `type(obj).__call__(obj, arg)` is consistent with the other dunder operators. The semantics with `*args, **kwargs` then follow naturally from the single-arg semantics.
This commit is contained in:
parent
8d8729146f
commit
6587fc60d4
6 changed files with 62 additions and 0 deletions
|
@ -250,6 +250,17 @@ Operations which work with sequences (some of them with mappings too) include:
|
||||||
|
|
||||||
.. versionadded:: 3.4
|
.. versionadded:: 3.4
|
||||||
|
|
||||||
|
|
||||||
|
The following operation works with callables:
|
||||||
|
|
||||||
|
.. function:: call(obj, / *args, **kwargs)
|
||||||
|
__call__(obj, /, *args, **kwargs)
|
||||||
|
|
||||||
|
Return ``obj(*args, **kwargs)``.
|
||||||
|
|
||||||
|
.. versionadded:: 3.11
|
||||||
|
|
||||||
|
|
||||||
The :mod:`operator` module also defines tools for generalized attribute and item
|
The :mod:`operator` module also defines tools for generalized attribute and item
|
||||||
lookups. These are useful for making fast field extractors as arguments for
|
lookups. These are useful for making fast field extractors as arguments for
|
||||||
:func:`map`, :func:`sorted`, :meth:`itertools.groupby`, or other functions that
|
:func:`map`, :func:`sorted`, :meth:`itertools.groupby`, or other functions that
|
||||||
|
|
|
@ -205,6 +205,14 @@ math
|
||||||
Dickinson in :issue:`44339`.)
|
Dickinson in :issue:`44339`.)
|
||||||
|
|
||||||
|
|
||||||
|
operator
|
||||||
|
--------
|
||||||
|
|
||||||
|
* A new function ``operator.call`` has been added, such that
|
||||||
|
``operator.call(obj, *args, **kwargs) == obj(*args, **kwargs)``.
|
||||||
|
(Contributed by Antony Lee in :issue:`44019`.)
|
||||||
|
|
||||||
|
|
||||||
os
|
os
|
||||||
--
|
--
|
||||||
|
|
||||||
|
|
|
@ -221,6 +221,12 @@ def length_hint(obj, default=0):
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
# Other Operations ************************************************************#
|
||||||
|
|
||||||
|
def call(obj, /, *args, **kwargs):
|
||||||
|
"""Same as obj(*args, **kwargs)."""
|
||||||
|
return obj(*args, **kwargs)
|
||||||
|
|
||||||
# Generalized Lookup Objects **************************************************#
|
# Generalized Lookup Objects **************************************************#
|
||||||
|
|
||||||
class attrgetter:
|
class attrgetter:
|
||||||
|
@ -423,6 +429,7 @@ __not__ = not_
|
||||||
__abs__ = abs
|
__abs__ = abs
|
||||||
__add__ = add
|
__add__ = add
|
||||||
__and__ = and_
|
__and__ = and_
|
||||||
|
__call__ = call
|
||||||
__floordiv__ = floordiv
|
__floordiv__ = floordiv
|
||||||
__index__ = index
|
__index__ = index
|
||||||
__inv__ = inv
|
__inv__ = inv
|
||||||
|
|
|
@ -518,6 +518,18 @@ class OperatorTestCase:
|
||||||
with self.assertRaises(LookupError):
|
with self.assertRaises(LookupError):
|
||||||
operator.length_hint(X(LookupError))
|
operator.length_hint(X(LookupError))
|
||||||
|
|
||||||
|
def test_call(self):
|
||||||
|
operator = self.module
|
||||||
|
|
||||||
|
def func(*args, **kwargs): return args, kwargs
|
||||||
|
|
||||||
|
self.assertEqual(operator.call(func), ((), {}))
|
||||||
|
self.assertEqual(operator.call(func, 0, 1), ((0, 1), {}))
|
||||||
|
self.assertEqual(operator.call(func, a=2, obj=3),
|
||||||
|
((), {"a": 2, "obj": 3}))
|
||||||
|
self.assertEqual(operator.call(func, 0, 1, a=2, obj=3),
|
||||||
|
((0, 1), {"a": 2, "obj": 3}))
|
||||||
|
|
||||||
def test_dunder_is_original(self):
|
def test_dunder_is_original(self):
|
||||||
operator = self.module
|
operator = self.module
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
A new function ``operator.call`` has been added, such that
|
||||||
|
``operator.call(obj, *args, **kwargs) == obj(*args, **kwargs)``.
|
|
@ -886,6 +886,27 @@ _operator__compare_digest_impl(PyObject *module, PyObject *a, PyObject *b)
|
||||||
return PyBool_FromLong(rc);
|
return PyBool_FromLong(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(_operator_call__doc__,
|
||||||
|
"call($module, obj, /, *args, **kwargs)\n"
|
||||||
|
"--\n"
|
||||||
|
"\n"
|
||||||
|
"Same as obj(*args, **kwargs).");
|
||||||
|
|
||||||
|
#define _OPERATOR_CALL_METHODDEF \
|
||||||
|
{"call", (PyCFunction)(void(*)(void))_operator_call, METH_FASTCALL | METH_KEYWORDS, _operator_call__doc__},
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
_operator_call(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
||||||
|
{
|
||||||
|
if (!_PyArg_CheckPositional("call", nargs, 1, PY_SSIZE_T_MAX)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return PyObject_Vectorcall(
|
||||||
|
args[0],
|
||||||
|
&args[1], (PyVectorcall_NARGS(nargs) - 1) | PY_VECTORCALL_ARGUMENTS_OFFSET,
|
||||||
|
kwnames);
|
||||||
|
}
|
||||||
|
|
||||||
/* operator methods **********************************************************/
|
/* operator methods **********************************************************/
|
||||||
|
|
||||||
static struct PyMethodDef operator_methods[] = {
|
static struct PyMethodDef operator_methods[] = {
|
||||||
|
@ -942,6 +963,7 @@ static struct PyMethodDef operator_methods[] = {
|
||||||
_OPERATOR_GE_METHODDEF
|
_OPERATOR_GE_METHODDEF
|
||||||
_OPERATOR__COMPARE_DIGEST_METHODDEF
|
_OPERATOR__COMPARE_DIGEST_METHODDEF
|
||||||
_OPERATOR_LENGTH_HINT_METHODDEF
|
_OPERATOR_LENGTH_HINT_METHODDEF
|
||||||
|
_OPERATOR_CALL_METHODDEF
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue