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 simple 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)
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.
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
- The Decorator Library on the Python wiki
- Understanding Python decorators - Stack Overflow
Related posts
- Fabric post-run processing Python decorator — posted 2010-11-06
- Using a Python timeout decorator for uploading to S3 — posted 2010-04-27
- Trying out a Retry decorator in Python — posted 2009-11-17
6
Comments
—
Comments feed for this post
#3 Aman commented on 2010-06-14:
Try this link also
http://arunnambyar.blogspot.com/2010/05/python-decorators-in-depth.html
Its Very usefull
#5 octopusgrabbus commented on 2011-04-08:
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.
#6 silopolis commented on 2012-04-18:
Thank you for your decorator related posts (and for many others). Thanks to commenters for additional links to which I'd add the following:
http://www.thumbtack.com/engineering/a-primer-on-python-decorators/
http://hairysun.com/books/decorators/
Just wished the second one had been available freely available and, at least, in a less crappy format...
Bests
Post a comment
About
I'm Eliot and this is my notepad for programming topics such as Python, Django, Ubuntu, Emacs, etc... more »
Search Blog
Tags
-
algorithms
(6)
-
android
(2)
-
aws
(10)
-
blogproject
(20)
-
c_cplusplus
(12)
-
cardstore
(8)
-
colinux
(2)
-
concurrency
(13)
-
conkeror
(2)
-
core
(2)
-
cygwin
(17)
-
datastructures
(15)
-
datetime
(4)
-
decorators
(4)
-
django
(41)
-
emacs
(22)
-
files_directories
(12)
-
git
(6)
-
hardware
(6)
-
install_setup
(8)
-
javascript
(3)
-
keyboard
(9)
-
matplotlib
(6)
-
mercurial
(4)
-
nginx
(2)
-
persistence
(6)
-
preferences
(7)
-
processes
(4)
-
pyqt
(18)
-
python
(157)
-
ratpoison
(3)
-
regexes
(6)
-
rsync
(3)
-
softwaretools
(17)
-
sql
(14)
-
ssh
(12)
-
subversion
(6)
-
twisted
(7)
-
ubuntu
(66)
-
urxvt
(5)
-
vxworks
(25)
-
webdev
(8)
-
wmii
(7)
Blogroll
- Adam Gomaa
- Alex Clemesha
- Amir Salihefendic
- Armin Ronacher
- David Beazley
- David Ziegler
- Duncan McGreggor
- Gareth Rushgrave
- Glyph Lefkowitz
- Guido van Rossum
- Ian Bicking
- Jacob Kaplan-Moss
- James Bennett
- James Tauber
- Jesper Noehr
- Marty Alchin
- Matt Harrison
- Nikolay Kolev
- Parand Darugar
- Peter Baumgartner
- Peter Bengtsson
- Rob Hudson
- Simon Willison
- Will McGugan
#1 PATX commented on 2010-04-14:
http://www.artima.com/weblogs/viewpost.jsp?thread=240808
Thats also a very good tutorial in case you are anyone else is interested...