We love designing and developing websites, but what really drives us is solving problems and cultivating strong relationships with our clients
Understanding decorators
By : shabda
If you used Django for any length of time, you would have come across the
login_required decorator. You write @login_required before a view, and it
magically becomes accessible only to authenticated users.
Decorators were introduced in python 2.4. PEP 318
is the PEP describing it. At
the simplest decorators are nothing but callables returning other callables, and
the decorator syntax @decorator is nothing but foo = bar(foo), where both
bar and foo are callables.
Let us see some decorators in action.
In [1]: def good_function():
...: print 'I am a good function'
...:
...:
In [2]: def decorator(orig_func):
...: def bad_func():
...: print 'I am a bad function'
...: return bad_func
...:
In [3]: good_function = decorator(good_function)
In [4]: good_function()
I am a bad function
In [5]: @decorator
....: def good_function2():
....: print 'I am a good function'
....:
....:
In [6]: good_function2()
I am a bad function
So you can see that the decorated function depended only on the value of the function returned by the decorator.
Here we discarded the function we were passed. Any useful decorator, decorates the original function, so it would use the original function. Let us see an actual decorator which may be useful.
def is_val_positive_deco(orig_func):
def temp_func(val):
if val < 0:
return 0
else:
return orig_func(val)
return temp_func
@is_val_positive_deco
def sqrt(val):
import math
return math.pow(val, (1.0/2))
print sqrt(-1)
print sqrt(4)
Here we defined an decorator is_val_positive_deco which will make functions
return 0, if the argument passed is negative. We can use this decorator to guard
against MathErrors.
Class based decorators
Decorators are just callables, and hence can be a class which has __call__
method. Sometimes they are easier to understand and reason about(than decorators
written as functions).
Lets see one,
class LogArgumentsDecorator(object):
def __init__(self, orig_func):
self.orig_func = orig_func
print 'started logging: %s' % orig_func.__name__
def __call__(self, *args, **kwargs):
print 'args: %s' % args
print 'kwargs:%s'% kwargs
return self.orig_func(*args, **kwargs)
@LogArgumentsDecorator
def sum_of_squares(a, b):
return a*a + b*b
print sum_of_squares(3, b=4)
This outputs,
started logging: sum_of_squares
args: 3
kwargs:{'b': 4}
25
Lets see what happens when we do,
@LogArgumentsDecorator
def sum_of_squares(a, b):
This is equivalent to
sum_of_squares = LogArgumentsDecorator(sum_of_squares)
At this point, we created a new LogArgumentsDecorator object, so
LogArgumentsDecorator.__init__(self, sum_of_squares) gets called. Hence
print 'started logging: %s' % orig_func.__name__ line is executed.
When we do sum_of_squares(...)
LogArgumentsDecorator.__call__ gets called with the passed values, where we
print the arguments and call the original function.
Here is one more example of a class based decorator. Here we rewrite(sort of, anyway) Django's login_required decorator as a class based decorator.
class LoginRequiredDecorator(object):
def __init__(self, orig_func):
self.orig_func = orig_func
def __call__(self, request, *args, **kwargs):
if request.user.is_authenticated():
self.orig_func(request, *args, **kwargs)
else:
return HttpResponseRedirect(reverse('...'))
Similar to above, it takes the view function, during __init__. When the request
comes, __call__ makes sure that user is authenticated, and takes action
appropriately.
Resources Decorator Library Pep 318
Subscribe to The Uswaretech Blog where we will be writing the next part of this tutorial explaining more complex decorators, decorators which take arguments, decorator factories and more. Or follow us on twitter.
Comments
this is excellent article, that lets me know deeply about decorator , thank :)
Django for any length of time has been a good login period.Only the authorised subcribers are being benefitted only by login .Decorators were introduced in python 2.4. PEP 318 is the PEP describing it.
very good explanation .But something about the parameter passing is missing...
i.e. in the second example of @is_val_positive_deco.
The passing value of function is is_val_positive_deco(val) is not explained clearly.
Reactions
Understanding decorators in Python http://ff.im/-4QkTa
This comment was originally posted on Twitter
One of the hidden gems of webframeworks: Decorators (You like to decorate ANY stuff. don’t ya?) http://tr.im/t7TP
This comment was originally posted on Twitter
@docdawning start here: http://bit.ly/rGWBz :) if you want a specific starting point with django/gae D me. #python #appengine #django
This comment was originally posted on Twitter
Understanding decorators — The Uswaretech Blog – Django Web…:  Bookmark this on Delicious – Saved by jamessnel.. http://bit.ly/Dt2JL
This comment was originally posted on Twitter
- How to use pep8.py to write better Django code
- Screencast: Django Tutorial Part 1
- How and why to use pyflakes to write better Python
- Getting started with South for Django DB migrations
- A brief overview of Vagrant
- Writing jQuery plugins using Coffeescript
- Behind the Scenes: Request to Response
- Using SQLite Database with Android
- Haml for Django developers
- Coffeescript for Python programmers
- rails
- django
- linkroundup
- django opinion
- opinion
- business
- API
- appengine
- python
- satire
- startup
- Uncategorized
- marketing
- personal
- rambling
- search
- interviews
- seo-interviews
- 5startupideas
- ideas
- seo
- tips
- forms
- paypal
- utilities
- datetime
- web2.0
- Amazon
- algorithms
- presentations
- products
- pinax
- satchmo
- ecommerce
- microsoft
- yahoo
- book
- tutorial
- models
- aggreagtion
- meta
- India
- apps
- about
- CSS
- Design
- wordpress
- test slug
- vim
- urls
- reviews
- javascript
- xmpp
- emacs
- Typography
- Grid Theory
- Color Theory
- iphone
- android
- titanium
- mobile applications
- CSS3
- Browser Compatibility
- mobile
- jobs
- lamson
- django setup
- files
- upload
- jsTree
- hierarchical view
- web page
- Treeview
- coffeescript
- request
- response
- South
- django south
- django migration
- --fake
- screencasts
- February 2012
- January 2012
- December 2011
- October 2011
- September 2011
- July 2011
- June 2011
- April 2011
- February 2011
- January 2011
- December 2010
- November 2010
- October 2010
- September 2010
- June 2010
- April 2010
- March 2010
- January 2010
- December 2009
- November 2009
- October 2009
- September 2009
- August 2009
- July 2009
- June 2009
- April 2009
- March 2009
- February 2009
- November 2008
- October 2008
- June 2008
- May 2008
- April 2008
Excellently and very simply described. Thanks!