Python decorator? - can someone please explain this?

The decorator syntax:

@protected(check_valid_user) 
def do_upload_ajax():
    "..."

is equivalent to

def do_upload_ajax():
    "..."
do_upload_ajax = protected(check_valid_user)(do_upload_ajax)

but without the need to repeat the same name three times. There is nothing more to it.

For example, here's a possible implementation of protected():

import functools

def protected(check):
    def decorator(func): # it is called with a function to be decorated
        @functools.wraps(func) # preserve original name, docstring, etc
        def wrapper(*args, **kwargs):
            check(bottle.request) # raise an exception if the check fails
            return func(*args, **kwargs) # call the original function
        return wrapper # this will be assigned to the decorated name
    return decorator

Take a good look at this enormous answer/novel. It's one of the best explanations I've come across.

The shortest explanation that I can give is that decorators wrap your function in another function that returns a function.

This code, for example:

@decorate
def foo(a):
  print a

would be equivalent to this code if you remove the decorator syntax:

def bar(a):
  print a

foo = decorate(bar)

Decorators sometimes take parameters, which are passed to the dynamically generated functions to alter their output.

Another term you should read up on is closure, as that is the concept that allows decorators to work.


A decorator is a function that takes a function as its only parameter and returns a function. This is helpful to “wrap” functionality with the same code over and over again.

We use @func_name to specify a decorator to be applied on another function.

Following example adds a welcome message to the string returned by fun(). Takes fun() as parameter and returns welcome().

def decorate_message(fun):

    # Nested function
    def addWelcome(site_name):
        return "Welcome to " + fun(site_name)

    # Decorator returns a function
    return addWelcome

@decorate_message
def site(site_name):
    return site_name;

print site("StackOverflow")

Out[0]: "Welcome to StackOverflow"

Decorators can also be useful to attach data (or add attribute) to functions.

A decorator function to attach data to func

def attach_data(func):
       func.data = 3
       return func

@attach_data
def add (x, y):
       return x + y

print(add(2, 3))
# 5    
print(add.data)
# 3