I have a situation where I am writing many functions of the form
def func(arg):
arg=pre_process(arg)
return do_work(arg)
I want to make it possible to do this preprocessing of arg in an easier way. I have tried to use decorators like in the following example
from typing import Callable
def super_decorator(arg_name: str, pre_fn: Callable) -> Callable:
def decorator(fn):
def inner(*args, **kwargs):
assert arg_name in kwargs.keys()
kwargs[arg_name] = pre_fn(arg_name)
return fn(*args, **kwargs)
return inner
return decorator
#example
def pre_processor(x):
return "pre-processed"
@super_decorator("arg1", pre_processor)
def func(*, arg1=None):
return arg1
print(func(arg1="hello world"))
Using this technique I get the correct output
pre-processed
However this is a bit hacky, and I have to force key-word arguments. Is there a better way?
The decorator you wrote is far more general than your first example requires. You could simply write
def compose(preprocessor):
def decorator(f):
def inner(arg):
return f(preprocessor(arg))
return inner
return decorator
@compose(pre_processor)
def func(arg):
return do_work(arg)
So in order to decide whether your super_decorator
is well designed, you need to more precisely define the problem it is trying to solve.
I used the name compose
because your superdecorator is just the curried form of a composition operator. If you know any Haskell, you would simply write
func = do_work . pre_processor