Proposal: add the function with the following logic to functools
module
def argorder(func, order):
def inner(*args, **kwds):
return func(*[args[i] for i in order], **kwds)
return inner
What issues is this a potential answer to:
a) It would improve efficient interactions between different modules in standard library. Specifically: functools
, itertools
and operator
b) There are already a lot of packages that have invented various variations of partial
to address issue which can be solved using this proposal. To name a few packages:
* partiell · PyPI
* partial-apply · PyPI
* partial · PyPI
* better-partial · PyPI
c) Also this is related to threads:
* Support for using partial with positional only argument functions - #3 by mariocj89
* Functools.partial extension to support specific positional arguments
c) Also directly related to: Builtins.any performance - #28 by dgrigonis
d) And somewhat related to: For any & every - #53 by Nineteendo as it improves performance of “short-circuiting” solutions that do not involve loop, but use map
function.
why is this better than all of the above?
a) More efficient solution to the problem when combined with functools.partial
compared to pure python external packages or to lambda
solution.
b) It doesn’t require any changes to existing code in contrast to modification proposals.
The most common response to making changes to functional tools regarding arguments is:
- “you can just use lambda”
However, this is a good argument when the cost is making existing tools (e.g. partial
) implementation more complex. While in this case, the proposal is well contained in itself and doesn’t require any changes to existing code.
It non-invasively improves performance by more than 50% compared to lambda
solution, which amounts to significant improvements when predicates are called on every iteration.
initial implementation
static PyObject *
argorder_call(argorder *self, PyObject *args, PyObject *kwds)
{
PyObject *new_args = PyTuple_New(self->nargs);
PyObject *arg, *index;
PyObject *result;
Py_ssize_t pos;
for (int i=0; i < self->nargs; i++) {
index = PySequence_Fast_GET_ITEM(self->order, i);
pos = PyLong_AsSize_t(index);
arg = PyTuple_GetItem(args, pos);
PyTuple_SET_ITEM(new_args, i, arg);
}
result = PyObject_Call(self->func, new_args, kwds);
Py_DECREF(new_args);
return result;
}
naming
Didn’t give much thought about it yet, I am open to suggestions, if this was considered.