Within the limits, everything after @ is done to create the decorator. In your first example, what follows after @ is just a name:
@p_decorate
therefore, Python looks at p_decorate and calls it with a decorated function as an argument:
get_text = p_decorate(get_text)
(simplified bit, get_text was not initially bound to the original function, but you already got it).
In your second example, the decorator expression is a bit more active, it includes a call:
@tags("p")
therefore, Python uses tags("p") to search for the decorator. In the end, this is what is then done:
get_text = tags("p")(get_text)
The output tags("p") here is a decorator! I call the tags function the factory decorator itself, it produces a decorator when called. When you call tags() , it returns tags_decorator() . This is a real decorator here.
Instead, you can remove the decorator function and hardcode "p" code and use it directly:
def tags_decorator_p(func): def func_wrapper(name): return "<{0}>{1}</{0}>".format("p", func(name)) return func_wrapper @tags_decorator_p def get_text(name):
but then you will need to create separate decorators for each possible value of the tags() argument. What is the value of the factory decorator, you can add parameters to the decorator and change the way you decorate your function.
The factory decorator can accept any number of arguments; it's just a function that you call to create a decorator. The decorator itself can take only one argument, a function to decorate.
I said within limits at the beginning of my answer for some reason; the syntax of the expression following @ allows only a dotted name ( foo.bar.baz , therefore access to the attribute) and a call ( (arg1, arg2, keyword=arg3) ). See the Help documentation. The original PEP 318 states:
The decorator's statement is limited by what it can accept - arbitrary expressions will not work. Guido preferred this because of the gut feeling [17].