Search code examples
pythonpython-3.xpython-decorators

How to intercept and preproccess arguments with decorators?


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?


Solution

  • 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