What is a decorator, really?

(with thanks to Fernando Perez for setting me straight on this stuff - see http://mail.scipy.org/pipermail/ipython-dev/2009-September/005500.html)

You may want to have a look at the Python docs:

The anatomy of the decorator thing is this:

@decorator-expression
function-definition

decorator-expression is an expression that returns a callable thing. The callable thing has to take single argument. That’s all it is. function-definition is a function definition (it therefore must begin with def). If decorator-expression is dec_func and function-definition is def func(): pass then the syntax above is exactly the result of:

def func(): pass
func = dec_func(func)

Decorator expression

The decorator expression is an expression that returns a callable thing.

For example, it could be a reference to a callable thing:

>>> def afunc(f): pass
>>> @afunc
... def bfunc(): pass

or an expression that returns a reference to a callable thing:

>>> def cfunc(value):
...    def anon_func(f):
...        return value
...    return anon_func
>>> @cfunc('a value')
... def bfunc(): pass

The callable thing can be anything that is callable - for example, a class:

>>> class C(object):
...     def __call__(self, value):
...         pass
>>> @C()
... def bfunc(): pass

The callable thing has to take one argument:

>>> def dfunc(): pass
>>> @dfunc
... def bfunc(): pass
Traceback (most recent call last):
  ...
TypeError: dfunc() takes no arguments (1 given)

and, the callable thing has to be callable:

>>> not_a_func = 'a string'
>>> @not_a_func
... def bfunc(): pass
Traceback (most recent call last):
   ...
TypeError: 'str' object is not callable

The decorator expression result

The decorator expression result is the result of evaluating the decorator expression.

For example, in this case:

>>> def cfunc(value):
...    def anon_func(f):
...        return value
...    return anon_func
>>> @cfunc('a value')
... def bfunc(): pass

the decorator expression result is equivalent to:

>>> def anon_func(f):
...     return 'a value'
>>> dec_exp_res = anon_func

Note that, the decorator expression result will process the function-definition like this:

>>> def func(): pass # function definition
>>> func = dec_exp_res(func)

That is what the syntax says. Usually, as in What is a decorator?, you will want to return a modified function. But, given the syntax, you can do anything you want:

>>> def strange_decorator(f):
...     print 'I am strange'
>>> @strange_decorator
... def bfunc(): pass
I am strange

This fits the syntax (the decorator expression resolves to a callable thing that takes one argument) but, this time, the decorator just prints something. This may seem a little bizarre, but - there are uses...