Python Decorator 3.0 and arguments to the decorator

decorator, python

Solution

In this case, you need to make your function return the decorator. (Anything can be solved by another level of indirection...)

from decorator import decorator
def substitute_args(arg_sub_dict):
  @decorator
  def wrapper(fun, arg):
    new_arg = arg_sub_dict.get(arg, arg)
    return fun(new_arg)
  return wrapper

This means `substitute_args` isn't a decorator itself, it's a decorator factory. Here's the equivalent without the `decorator` module.

def substitute_args(arg_sub_dict):
  def my_decorator(fun):
    def wrapper(arg):
      new_arg = arg_sub_dict.get(arg, arg)
      return fun(new_arg)
    # magic to update __name__, etc.
    return wrapper
  return my_decorator

Three levels deep isn't very convenient, but remember two of them are when the function is defined:

@substitute_args({}) # this function is called and return value is the decorator
def f(x):
  return x
# that (anonymous) decorator is applied to f

Which is equivalent to:

def f(x):
  return x
f = substitude_args({})(f) # notice the double call

Problem

I'm excited to see the latest version of the `decorator` python module (3.0). It looks a lot cleaner (e.g. the syntax is more sugary than ever) than previous iterations. However, it seems to have lousy support (e.g. "sour" syntax, to horribly stretch the metaphor) for decorators that take arguments themselves. Does anyone have a good example for how you'd cleanly do this using `decorator` 3.0? ``` def substitute_args(fun, arg_sub_dict): def wrapper(arg): new_arg = arg_sub_dict.get(arg, arg) return fun(new_arg) # some magic happens here to make sure that type signature, # __name__, __doc__, etc. of wrapper matches fun return wrapper ```

Original source