operator.call / operator.__call__

A simple suggestion: add "operator.call" and "operator.__call__", which would provide a function like Python2's "apply" (but it'd be called with already unpacked arguments, i.e. operator.call(f, *args, **kwargs)). Why? To be able to pass it as an argument to other function, just like the other functions defined in the "operator" module. Antony

On Wed, Oct 29, 2014 at 03:39:59PM -0700, Antony Lee wrote:
I think you want something like this? def call(callable, *args, **kwargs): return callable(*args, **kwargs) Can you give an example of how you might use this call method? It doesn't have to be a real world use-case, just an illustration. Perhaps I'm being a bit dim-witted today, but I'm having trouble thinking of where I would use this operator.call rather than just directly applying *args, **kwargs to the callable. -- Steven

I have two use cases below. Yes, it is true that just defining the "call" function myself would only take me two lines, but on the other hand the same is true for most functions in the operator module... - Sometimes, depending on a switch, you want either to call a function directly, or to pass it to a specialized "caller", e.g. def run_in_thread(func, *args, **kwargs): Thread(target=func, args=args, kwargs=kwargs).start() def run_here_or_in_thread(in_thread, func, *args, **kwargs): (run_in_thread if in_thread else operator.call)(func, *args, **kwargs) or to optionally use a ContextDecorator: def run_in_ctx(ctx, func, *args, **kwargs): (ctx or operator.call)(func) - In Qt programs (although I assume similar ideas apply to other GUI toolkits), where functions that operate on the GUI can only be called from the main thread, but "signals" (in the Qt sense of the term) can be used to communicate between threads, I find it useful to define a "call this in the GUI thread" generic signal. The implementation is essentially class Main(QMainWindow): any_callable_signal = pyqtSignal(object) def __init__(self, *args, **kwargs): <...> self.any_callable_signal.connect(lambda f: f()) # <- operator.call seems to express this better. def call_in_gui_thread(self, func): self.any_callable_signal.emit(func) Antony 2014-10-29 17:57 GMT-07:00 Steven D'Aprano <steve@pearwood.info>:

On 10/30/2014 4:07 AM, Antony Lee wrote:
The primary intended use of operator.op functions is to be passed as arguments since operators themselves cannot be. By exposing C-coded wrappers, they make this possible more efficiently than would be the case with Python wrappers. There never seemed to be a need to pass 'apply' itself as an argument, and the newer of f(*args, **kwds) made its direct use unneeded. Hence it was deleted. The signature of apply is apply(func, arg[, keywords]). The arguments are not unpacked just to be repacked and unpacked again, as would happen with your renamed version of apply.
- Sometimes, depending on a switch, you want either to call a function directly, or to pass it to a specialized "caller", e.g.
Then either call it directly or pass it to a specialized caller.
def run_in_thread(func, *args, **kwargs): Thread(target=func, args=args, kwargs=kwargs).start()
In its use below, this would be more efficient as def run_in_thread(func, args, kwargs):
def run_here_or_in_thread(in_thread, func, *args, **kwargs): (run_in_thread if in_thread else operator.call)(func, *args, **kwargs)
With the altered sig, this can be written (run_in_thread(func, args, kwargs) if in_thread else func(*args, **kwargs)) -- Terry Jan Reedy

On Wed, Oct 29, 2014 at 03:39:59PM -0700, Antony Lee wrote:
I think you want something like this? def call(callable, *args, **kwargs): return callable(*args, **kwargs) Can you give an example of how you might use this call method? It doesn't have to be a real world use-case, just an illustration. Perhaps I'm being a bit dim-witted today, but I'm having trouble thinking of where I would use this operator.call rather than just directly applying *args, **kwargs to the callable. -- Steven

I have two use cases below. Yes, it is true that just defining the "call" function myself would only take me two lines, but on the other hand the same is true for most functions in the operator module... - Sometimes, depending on a switch, you want either to call a function directly, or to pass it to a specialized "caller", e.g. def run_in_thread(func, *args, **kwargs): Thread(target=func, args=args, kwargs=kwargs).start() def run_here_or_in_thread(in_thread, func, *args, **kwargs): (run_in_thread if in_thread else operator.call)(func, *args, **kwargs) or to optionally use a ContextDecorator: def run_in_ctx(ctx, func, *args, **kwargs): (ctx or operator.call)(func) - In Qt programs (although I assume similar ideas apply to other GUI toolkits), where functions that operate on the GUI can only be called from the main thread, but "signals" (in the Qt sense of the term) can be used to communicate between threads, I find it useful to define a "call this in the GUI thread" generic signal. The implementation is essentially class Main(QMainWindow): any_callable_signal = pyqtSignal(object) def __init__(self, *args, **kwargs): <...> self.any_callable_signal.connect(lambda f: f()) # <- operator.call seems to express this better. def call_in_gui_thread(self, func): self.any_callable_signal.emit(func) Antony 2014-10-29 17:57 GMT-07:00 Steven D'Aprano <steve@pearwood.info>:

On 10/30/2014 4:07 AM, Antony Lee wrote:
The primary intended use of operator.op functions is to be passed as arguments since operators themselves cannot be. By exposing C-coded wrappers, they make this possible more efficiently than would be the case with Python wrappers. There never seemed to be a need to pass 'apply' itself as an argument, and the newer of f(*args, **kwds) made its direct use unneeded. Hence it was deleted. The signature of apply is apply(func, arg[, keywords]). The arguments are not unpacked just to be repacked and unpacked again, as would happen with your renamed version of apply.
- Sometimes, depending on a switch, you want either to call a function directly, or to pass it to a specialized "caller", e.g.
Then either call it directly or pass it to a specialized caller.
def run_in_thread(func, *args, **kwargs): Thread(target=func, args=args, kwargs=kwargs).start()
In its use below, this would be more efficient as def run_in_thread(func, args, kwargs):
def run_here_or_in_thread(in_thread, func, *args, **kwargs): (run_in_thread if in_thread else operator.call)(func, *args, **kwargs)
With the altered sig, this can be written (run_in_thread(func, args, kwargs) if in_thread else func(*args, **kwargs)) -- Terry Jan Reedy
participants (6)
-
Andrew Barnert
-
Antony Lee
-
Jonas Wielicki
-
Steven D'Aprano
-
Terry Reedy
-
Yann Kaiser