SaltyCrane Blog — Notes on JavaScript and web development

Two of the simplest Python decorator examples

After trying for about the fifth time, I think I am starting to understand Python decorators due largely to Jack Diederich's PyCon 2009 talk, Class Decorators: Radically Simple.

Jack's practical definition of a decorator is:

  • A function that takes one argument
  • Returns something useful

In many cases, a function decorator can be described more specifically:

  • A function that takes one argument (the function being decorated)
  • Returns the same function or a function with a similar signature

As Jack states in his talk, a decorator is merely syntactic sugar. The same functionality can be achieved without using the decorator syntax. This code snippet:

@mydecorator
def myfunc():
    pass

is equivalent to:

def myfunc():
    pass
myfunc = mydecorator(myfunc)

Here are two of the simplest examples from Jack's talk:

Identity decorator

This is the simplest decorator. It does nothing. It takes the decorated function as an argument and returns the same function without doing anything.

def identity(ob):
    return ob

@identity
def myfunc():
    print "my function"

myfunc()
print myfunc
my function
<function myfunc at 0xb76db17c>

Hello world decorator

I am dumb. This one doesn't do what it's supposed to.

This decorator prints "Hello world" before returning the decorated function.

def helloworld(ob):
    print "Hello world"
    return ob

@helloworld
def myfunc():
    print "my function"

myfunc()
print myfunc
Hello world
my function
<function myfunc at 0xb78360d4>

A simple decorator that actually does something (and is not broken like the Hello world decorator above)

This decorator is used to print some text before and after calling the decorated function. Most of the time the decorated function is wrapped by a function which calls the decorated function and returns what it returns. ?When is a wrapper not needed?

from functools import wraps

def mydecorator(f):
    @wraps(f)
    def wrapped(*args, **kwargs):
        print "Before decorated function"
        r = f(*args, **kwargs)
        print "After decorated function"
        return r
    return wrapped

@mydecorator
def myfunc(myarg):
    print "my function", myarg
    return "return value"

r = myfunc('asdf')
print r
Before decorated function
my function asdf
After decorated function
return value

What if I want to pass arguments to the decorator itself (not the decorated function)?

A decorator takes exactly one argument so you will need a factory to create the decorator. Unlike the previous example, notice how the factory function is called with parentheses, @mydecorator_not_actually(count=5), to produce the real decorator.

from functools import wraps

def mydecorator_not_actually(count):
    def true_decorator(f):
        @wraps(f)
        def wrapped(*args, **kwargs):
            for i in range(count):
                print "Before decorated function"
            r = f(*args, **kwargs)
            for i in range(count):
                print "After decorated function"
            return r
        return wrapped
    return true_decorator

@mydecorator_not_actually(count=5)
def myfunc(myarg):
    print "my function", myarg
    return "return value"

r = myfunc('asdf')
print r
Before decorated function
Before decorated function
Before decorated function
Before decorated function
Before decorated function
my function asdf
After decorated function
After decorated function
After decorated function
After decorated function
After decorated function
return value

References / See also

Comments


#2 Eliot commented on :

PATX: That is a great article. Thanks!


#3 Aman commented on :

Try this link also

http://arunnambyar.blogspot.com/2010/05/python-decorators-in-depth.html

Its Very usefull


#4 devid commented on :

I love and like decorators Chelmsford


#5 octopusgrabbus commented on :

Thanks for the examples. Unlike a lot of other Python documentation, I am not finding clear explanations in the online Python documation. So, again, thank you.


#7 Bob Stein commented on :

Loved how you start with an ultra simple example in actual Python. Hugely helpful.

Crestfallen how your first example has been crossed out. The next first example is so complicated. Nested decoration! My brain is mush. Suggest a hello world decorator is feasible and deserves a home here. Anyway, here's a much simpler working decorator: https://stackoverflow.com/a...

disqus:3544450453