0

I am trying to understand the functioning of decorators. What am i doing wrong in the following code. Please do correct it

As I have understood when aFunction() is called it in turn calls myDecorator() which also makes a call to afunction(). Right?

Also how to pass parameters into afunction()

class myDecorator(object):

    def __init__(self, f):
        print "inside myDecorator.__init__()"
        f(1) # Prove that function definition has completed

    def __call__(self):
        print "inside myDecorator.__call__()"

@myDecorator
def aFunction(*a):
    print a
    print "inside aFunction()"

print "Finished decorating aFunction()"

aFunction(2)
glglgl
  • 89,107
  • 13
  • 149
  • 217
Rajeev
  • 44,985
  • 76
  • 186
  • 285
  • 2
    Thorough explanation here: http://stackoverflow.com/questions/739654/understanding-python-decorators – rplnt Sep 27 '11 at 13:08
  • If you need more help with decorators and annotations see my blog post here. http://blog.mattalcock.com/2013/1/5/decorates-and-annotations/ – Matt Alcock Feb 04 '13 at 22:25

3 Answers3

4
class myDecorator(object):

    def __init__(self, f):
        print "inside myDecorator.__init__()"
        # save a reference to the real function, so it can be called later
        self.f = f

    def __call__(self, *args, **kwargs):
        print "inside myDecorator.__call__()"
        # call the real function and return its result
        # passing it any and all arguments
        return self.f(*args, **kwargs)

@myDecorator
def aFunction(*a):
    print a
    print "inside aFunction()"

print "Finished decorating aFunction()"

aFunction(1)

print "Finished calling aFunction()
agf
  • 171,228
  • 44
  • 289
  • 238
2

Your __call__ method is missing the parameter, which you give to aFunction.

class myDecorator(object):

    def __init__(self, f):
        print "inside myDecorator.__init__()"
        f(1) # Prove that function definition has completed
        self.__function = f

    def __call__(self, *args):
        # the *args magic is here to mirror the original parameter list of
        # the decorated function. But it is better to place here parameter list
        # of the function you want to decorate, in order to minimize error possibilities
        print "inside myDecorator.__call__()"
        return self.__function(*args)

@myDecorator
def aFunction(*a):
    print a
    print "inside aFunction()"

print "Finished decorating aFunction()"

aFunction(1)
aFunction('a', 23, 42)
Rudi
  • 19,366
  • 3
  • 55
  • 77
  • 1
    You should return the result of the function from `__call__`. There is also most likely no need to use name mangling here -- you may even want people to be able to access the wrapped function. You're assuming the function doesn't take any keyword arguments. – agf Sep 27 '11 at 13:14
  • @agf I agree with the return, but as for the "visibility" of the function member and the function parameters, it depends on the real environment. – Rudi Sep 27 '11 at 13:22
1

f, in __init__, needs to be saved, then the __call__ method needs to call it. Something like this:

class myDecorator(object):
    def __init__(self, f):
        print "inside myDecorator.__init__()"
        self.f = f
        print "function has been saved"
    def __call__(self, *args):
        print "inside myDecorator.__call__()"
        result = self.f(args)
        print "done with f()"
        return result

@myDecorator
def aFunction(*a):
    print a
    print "inside aFunction()"

aFunction(1)

What happens with decoration is that the original function is replaced with whatever the decorator returns. Your original code, however, was not saving any reference to aFunction so it was getting lost.

Ethan Furman
  • 63,992
  • 20
  • 159
  • 237