×
By the end of this chapter, you should be able to:
Decorators are functions that "decorate," or enhance, other functions. In order to see what this means, let's first review how we can pass functions to other functions. Remember, everything in Python is an object and objects are first class!
def shout(): return "WHOA!" def whisper(): return "Shhhh" def perform_action(func): print("something is happening") return func() perform_action(shout) # something is happening # 'WHOA!' perform_action(whisper) # something is happening # 'Shhhh'
We can write the behavior of a decorator like this:
def new_decorator(func): def wrap_func(): print("code before func!") func() print("code after func!") return wrap_func def decorate_me(): print("decorate me!") decorate_me = new_decorator(decorate_me) decorate_me() # What do you think this will print?
Let's now use the decorator syntax to do the same thing! When you use a decorator, the function being used to decorate is prefixed with an @
symbol. The function you're decorating is then defined below. Take a look:
def new_decorator(func): def wrap_func(): print("code before func!") func() print("code after func!") return wrap_func @new_decorator def decorate_me(): print("decorate me!")
Note how the code inside of the new_decorator
function decorates, or enhances, the code inside of the decorate_me
function.
Let's revisit the first example but refactor it to use decorator syntax.
def perform_action(func): def wrap_func(): print("something is happening") return func() return wrap_func @perform_action def whisper(): return "Shhhh" @perform_action def shout(): return "WHOA!" whisper() # something is happening # 'Shhhh' shout() # something is happening # 'WHOA!'
This code will work just fine, but if we examine the __name__
or __doc__
attribute for our function it will not be correct!
shout.__name__ # 'wrap_func' - oops!
We can manually fix this, or we can use the wraps decorator from the functools module.
from functools import wraps def perform_action(func): @wraps(func) def wrap_func(): print("something is happening") return func() return wrap_func @perform_action def whisper(): return "Shhhh" @perform_action def shout(): return "WHOA!" shout.__name__ # 'shout' - much better
When you're ready, move on to Lambdas and Dates