Decorator that supplies arguments to functions I have assignment to generate argument based decorator I wrote like this.

def my_decorator(*deco_args): 
    def wrap(f):
        def wrapped_f(*func_args):
            if len(deco_args) == 1 and len(func_args) ==1:
                return f(func_args[0], deco_args[0])
            elif len(deco_args) == 2 and len(func_args) == 2:
                return f(*(deco_args+func_args))
        return wrapped_f
    return wrap

@my_decorator(2)
def pow(x, y): 
    return x ** y

print pow(4) #=&gt; 16

@my_decorator("/home", "user")
def path(*args):
   return "/".join(args)

print path("videos", "cats.png") #=&gt; "/home/user/videos/cats.png"


Is there any better way to do this ?
I don't think my_decorator is a very descriptive name, but maybe that's just part of the assignment.  Also, f isn't a very descriptive name for the function you are decorating.

I did my own test:

&gt;&gt;&gt; @my_decorator(2)
... def here(*args):
...     print args
... 
&gt;&gt;&gt; here(4, 5)
&gt;&gt;&gt; 


Do you know why it doesn't print anything?  It's because you have if and elif in wrapped_f, but one argument to my_decorator and two arguments to here doesn't match either of your conditions, so wrapped_f doesn't know what to do.  To be safe, it does not call the function and just returns None.  That always happens when you don't tell a function what to return: it returns None.  My question is, why do you have those conditions?  I would change that function to:

def wrapped_f(*func_args):
    return f(*(deco_args+func_args))




Your code really has only four lines of reviewable code, so I will just suggest a new (not necessarily better) way:

from functools import partial

class MyDecorator:
    def __init__(self, *args):
        self.args = args
    def __call__(self, func):
        return partial(func, *self.args)


functools.partial takes a function and any other arguments and returns a callable object that, when called, calls the function with the original arguments and whatever other arguments are given.  Our decorator is called with 2 for my above example, so it sets self.args to (2,).  When our MyDecorator object is called (with here as an argument), the __call__ method is executed and we return a partial object with that function and the arguments we got earlier.  Therefore, when the result is called with more arguments, it calls the function with the arguments originally given to the decorator as well as the arguments being given currently.  You can see that partial is very similar to your decorator.  We just needed to make it decorator-compatible.



Edit: As mentioned by @JoeWallis in the comments, you could still use partial() in nested functions similar to yours:

def my_decorator(*deco_args):
    def wrap(f):
        return partial(f, *deco_args)
    return wrap