2

I'm currently trying out decorators and I can't understand one thing. I have simple decorator:

def new_decorator(func):
    print "Calling new_decorator()"
    def wrap(arg):
        print "Calling wrap()"
        func(arg)
    return wrap  

@new_decorator
def foo(name):
    print name

Upon running we get:

'Calling decorate()' 

Only after calling foo:

>>> foo('Jon')
Calling wrap()
Jon

Till now I understand everything (I think). new_decorator(func) is called at the start, with foo as parameter and it returns wrap. But now I tried decorators with parameters:

def add_attr(varname, value):
    def decorate(func):
        print "Calling decorate()"
        setattr(func, varname, value)
        return func
    return decorate

@add_attr('var', 'New attribute')
def foo():
    print "Calling foo()"
    print foo.var

When running it (without calling foo()) it returns:

'Calling decorate()'

After foo():

>>> foo()
Calling foo()
New attribute

What I can't understand is, why this "inner" function decorate is called at the start, before even calling foo? In first example it wasn't. And how was function foo send as a parameter to decorate? add_attr gets only 2 parameters, and neither of them is foo.

K. Macieja
  • 23
  • 1
  • 5

1 Answers1

4

You generally need 3 layers of nesting for a decorator which accepts arguments. Think of a decorator which accepts arguments as a "decorator maker". It should return a decorator when called.

To understand this, consider that the code below

@new_decorator
def foo(name):
    print name

Is really just syntax sugar for this:

def foo(name):
    print name

foo = new_decorator(foo)

So, similarly, this:

@add_attr('var', 'New attribute')
def foo():
    print "Calling foo()"
    print foo.var

Is identical to this:

def foo():
    print "Calling foo()"
    print foo.var

foo = add_attr('var', 'New attribute')(foo)

That should guide you in the correct direction for writing add_attr correctly.

If you're still confused after making a few attempts, I refer you to a famous answer from e-satis that explains decorators better than anything else I've seen on the web.

Community
  • 1
  • 1
wim
  • 338,267
  • 99
  • 616
  • 750