Question

Is it possible to pass the decorated method with arguments to __init__ of an decorator?

A simple decorator and usage example

class Decorator(object):
    def __init__(self, *args):
        print args

    def __call__(self, func): # yep the method still have to be callable
        return func

@Decorator
def foo():
    pass

A decorator without arguments will pass the method as argument

$ python foo.py
(<function foo at 0x7fefd7ac1b90>,)

When I add arguments to the decorator

@Decorator(1, 2, 3)
def foo():
    pass

it results in

$ python test.py 
(1, 2, 3)

As you can see the method is now missing in the passed arguments.

Was it helpful?

Solution

When we pass arguments to a decorator we need to create an additional function that accepts those arguments and then returns the actual decorator:

def decorator_creator(*args):
    class Decorator(object):
        def __init__(self, func):
            print args
            print func
            self.func = func
        def __call__(self):
            return self.func()
    return Decorator

@decorator_creator(1, 2, 3)
def foo():
    pass

Output:

(1, 2, 3)
<function foo at 0x0000000002EB9EB8>

OTHER TIPS

An alternative that doesn't need inner classes:

class decorator(object):
    def __init__(self, *args):
        # This creates the decorator
        self.args = args

    def __call__(self, func):
        # This applies the decorator
        self.func = func
        return self.call

    def call(self, *moreargs):
        # And this happens when the original function is called
        print self.args, self.func, moreargs
        return self.func()

@decorator(1, 2, 3)
def foo():
    pass

I've also made use of functools.partial(self.method, func) for decorators. Sometimes useful.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top