You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Adding a call/call function to the operator module (where operator.call(*args, **kwargs)(func) == func(*args, **kwargs), similarly to operator.methodcaller) seems consistent with the design with the rest of the operator module.
An actual use case I had for such an operator was collecting a bunch of callables in a list and wanting to dispatch them to concurrent.futures.Executor.map, i.e. something like executor.map(operator.call, funcs) (to get the parallelized version of [func() for func in funcs]).
Actually, upon further thought, the semantics I suggested above should go into operator.caller (cf. operator.methodcaller), and operator.call/operator.__call__ should instead be defined as operator.call(f, *args, **kwargs) == f(*args, **kwargs), so that the general rule operator.opname(a, b) == a.__opname__(b) (modulo dunder lookup rules) remains applicable.
I'm not convinced that operator.caller() would be useful to me. Why do you consider that it belongs to the stdlib? It is a common pattern? Did you see in this pattern in the current stdlib?
Can't you easily implement such helper function in a few lines of Python?
operator documentation says: "The operator module exports a set of efficient functions corresponding to the intrinsic operators of Python". I don't see how operator.caller() implements an existing "intrinsic operators of Python".
methodcaller() can be implemented in 4 lines of Python, as shown in its documentation:
---
An actual use case I had for such an operator was collecting a bunch of callables in a list and wanting to dispatch them to concurrent.futures.Executor.map, i.e. something like executor.map(operator.call, funcs) (to get the parallelized version of [func() for func in funcs]).
Can't you use functools.partial() for that?
anntzer commented on Aug 30, 2021
anntzermannequin
MannequinAuthor
More actions
I'm not convinced that operator.caller() would be useful to me.
To be clear, as noted above, I have realized that the semantics I initially proposed (now known as "caller") are not particularly useful; the semantics I am proposing (and implementing in the linked PR) are call(f, *args, **kwargs) == f(*args, **kwargs).
I don't see how operator.caller() implements an existing "intrinsic operators of Python".
Agreed; on the other hand function calling is much more intrinsic(?!)
Can't you use functools.partial() for that?
How do you propose to do that? Perhaps I am missing an easy solution...
I agree that both functions can be written in two (or one) line, but the same can be said of most functions in the operator module (def add(x, y): return x + y); from the module's doc ("efficient functions corresponding to the intrinsic operators"), I would argue that the criteria for inclusion are efficiency (operator.call is indeed fast, see the linked PR) and intrinsicness (I don't know if there's a hard definition, but function calling certainly seems intrinsic).
@terryjreedy Thanks! I have a python implementation already but it is a little slower than I'd like so I was hoping the c implementation in the operator module might be a little faster.
Activity
anntzer commentedon May 3, 2021
Adding a call/call function to the operator module (where
operator.call(*args, **kwargs)(func) == func(*args, **kwargs), similarly to operator.methodcaller) seems consistent with the design with the rest of the operator module.An actual use case I had for such an operator was collecting a bunch of callables in a list and wanting to dispatch them to concurrent.futures.Executor.map, i.e. something like
executor.map(operator.call, funcs)(to get the parallelized version of[func() for func in funcs]).anntzer commentedon Aug 4, 2021
Actually, upon further thought, the semantics I suggested above should go into
operator.caller(cf.operator.methodcaller), andoperator.call/operator.__call__should instead be defined asoperator.call(f, *args, **kwargs) == f(*args, **kwargs), so that the general ruleoperator.opname(a, b) == a.__opname__(b)(modulo dunder lookup rules) remains applicable.mdickinson commentedon Aug 23, 2021
This seems like a reasonable addition to me. Victor: any thoughts?
vstinner commentedon Aug 30, 2021
Python 2.7 had apply(func, args, kwargs) which called func(*args, **kwargs).
https://docs.python.org/2.7/library/functions.html#apply
There is also functools.partial(func, *args, **kwargs)(*args2, **kwargs2) which calls func(*args, *args2, **kwargs, **kwargs2).
https://docs.python.org/dev/library/functools.html#functools.partial
operator.methodcaller(name, /, *args, **kwargs)(obj) calls getattr(obj, name)(*args, **kwargs).
https://docs.python.org/dev/library/operator.html#operator.methodcaller
I'm not convinced that operator.caller() would be useful to me. Why do you consider that it belongs to the stdlib? It is a common pattern? Did you see in this pattern in the current stdlib?
Can't you easily implement such helper function in a few lines of Python?
operator documentation says: "The operator module exports a set of efficient functions corresponding to the intrinsic operators of Python". I don't see how operator.caller() implements an existing "intrinsic operators of Python".
methodcaller() can be implemented in 4 lines of Python, as shown in its documentation:
---
vstinner commentedon Aug 30, 2021
Can't you use functools.partial() for that?
anntzer commentedon Aug 30, 2021
To be clear, as noted above, I have realized that the semantics I initially proposed (now known as "caller") are not particularly useful; the semantics I am proposing (and implementing in the linked PR) are
call(f, *args, **kwargs) == f(*args, **kwargs).Agreed; on the other hand function calling is much more intrinsic(?!)
How do you propose to do that? Perhaps I am missing an easy solution...
vstinner commentedon Aug 31, 2021
So you can want to reintroduce the Python 2 apply() function which was removed in Python 3.
You can reimplement it in 2 lines, no?
anntzer commentedon Sep 1, 2021
Python2's apply has different semantics: it takes non-unpacked arguments, i.e.
rather than
I agree that both functions can be written in two (or one) line, but the same can be said of most functions in the operator module (def add(x, y): return x + y); from the module's doc ("efficient functions corresponding to the intrinsic operators"), I would argue that the criteria for inclusion are efficiency (operator.call is indeed fast, see the linked PR) and intrinsicness (I don't know if there's a hard definition, but function calling certainly seems intrinsic).
mdickinson commentedon Sep 24, 2021
New changeset 6587fc6 by Antony Lee in branch 'main':
bpo-44019: Implement operator.call(). (GH-27888)
6587fc6
mdickinson commentedon Sep 24, 2021
Thanks for the contribution!
mdickinson commentedon Sep 24, 2021
New changeset bfe26bb by Terry Jan Reedy in branch 'main':
bpo-44019: Add missing comma to operator.call doc (GH-28551)
bfe26bb
corona10 commentedon Oct 21, 2021
New changeset a53456e by Kreus Amredes in branch 'main':
bpo-44019: Add operator.call() to __all__ for the operator module (GH-29110)
a53456e
vstinner commentedon Oct 21, 2021
test___all__ was not supposed to fail with the missing "call" in operator.__all__?
corona10 commentedon Oct 21, 2021
AFAIK, it doesn't check.
I add the test for the operator module.
corona10 commentedon Oct 21, 2021
New changeset 37fad7d by Dong-hee Na in branch 'main':
bpo-44019: Add test_all_exported_names for operator module (GH-29124)
37fad7d
mrucker commentedon Dec 29, 2022
I'd really like to use this in python 3.7. Any chance there is a python package available which backports this?
terryjreedy commentedon Dec 29, 2022
operatoris written in python, so you can copy anything you want into your code, or even monkeypatchoperator.mrucker commentedon Dec 29, 2022
@terryjreedy Thanks! I have a python implementation already but it is a little slower than I'd like so I was hoping the c implementation in the operator module might be a little faster.