What is a decorator?¶
- A decorator is
a function, that takes a function as input, and returns a function
What is a decorator again?
- A decorator is
a function, that takes a function as input, and returns a function
Is that really what a decorator is?
No, it isn’t (see What is a decorator, really?) but it is almost always what a decorator is. So, for now, let’s pretend. Honestly, it will help.
Here’s an example of a simple decorator:
>>> def mydec(original_func):
... print 'Am preparing the function'
... def _decorating_function(*args):
... print 'I am running the original function'
... val = original_func(*args)
... print 'I am returning the value from the original function'
... return val
... print 'Done preparing, returning new function'
... return _decorating_function
Note that mydec
takes a function as input, and returns a
function as output.
Now, let’s say we have some function f1
>>> def f1(arg):
... return arg * 10
...
>>> f1(2)
20
We can decorate it with our decorator. You’ll see the decoration happening in the output below.
>>> f2 = mydec(f1)
Am preparing the function
Done preparing, returning new function
Now, running the decorated function (f2
) reveals the print
statements we put in, in the new function, that the decorator returned.
>>> f2(2)
I am running the original function
I am returning the value from the original function
20
This is all very ordinary Python. But, as of Python 2.4, there is a
special syntax for applying a decorator to a function being
defined. It uses the @
symbol. We can use our decorator like this:
>>> @mydec
... def f3(arg):
... return arg * 20
...
Am preparing the function
Done preparing, returning new function
Running it shows our print statements again:
>>> f3(2)
I am running the original function
I am returning the value from the original function
40
The @
is just a syntax addition, and does exactly the following:
>>> def f3(arg):
... return arg * 20
...
>>> f3 = mydec(f3)
Am preparing the function
Done preparing, returning new function
which gives exactly the same result as we saw above
>>> f3(2)
I am running the original function
I am returning the value from the original function
40
Using decorators with the @
syntax can be more complicated.
The ‘@’ syntax allows you to put in an expression that returns a
decorator. Obviously, above, the expression 'mydec'
returns the
decorating function mydec
. But, you can also enter a more
complicated expression that returns a decorator. A decorator is:
a function, that takes a function as input, and returns a
function
for example:
>>> def dec_maker(scale_by):
... # This function, returns a decorator
... # A decorator is: a function, that takes a function as
... # input, and returns a function
... print 'About to make the decorator'
... def actual_decorator(func):
... print 'Applying the actual decorator'
... def _decorated_func(*args):
... print 'Running decorated func'
... val = func(*args)
... print 'Scaling original return value by %s' % scale_by
... return val * scale_by
... return _decorated_func
... return actual_decorator
Without the @
syntax, you could use dec_maker
like this
>>> resulting_decorator = dec_maker(100)
About to make the decorator
>>> f4 = resulting_decorator(f1)
Applying the actual decorator
>>> f4(2)
Running decorated func
Scaling original return value by 100
2000
The @ equivalent is this:
>>> @dec_maker(100)
... def f4(arg):
... return arg * 10
...
About to make the decorator
Applying the actual decorator
>>> f4(2)
Running decorated func
Scaling original return value by 100
2000