Tuesday, March 27, 2012

Python Decorator – A Syntactic Sugar

Python Decorator - A Syntactic Sugar

Sweet!!! And that's why python decorators are called as syntactic sugar. So what are decorators in python anyway? If you are newbie, it might confuse a lot at first. The idea is simple. To take a function, and return another function. As the name suggests, it decorates a function. Here I am trying to explain only the basic working of the decorators. I ll post a more detailed post on decorator when I find time. So lets consider a baby program to start with: to print the entered string. I think the following program do not need any explanation.

#First Example
import sys

def originalFunction(stringArg):
    print "The entered String is :"
    print stringArg

def main():
    print "Enter a String :"
    strInput = sys.stdin.readline()
    originalFunction(strInput)

if __name__ == "__main__":
    main()

The function does not do much. It just prints the string you entered in the console. The output looks some what like this:

Enter a String :
dhilipsiva
The entered String is :
dhilipsiva

well, that was not so hard. Having done that, now lets dive into decorator and apply it to the first example. As I already said, a decorator takes a function and return another function. A decorator is denoted by a '@' symbol in its beginning. Using the first example, lets consider we have to use a decorator '@CAPITALIZED' which alters the 'originalFunction' so that it prints the capitalized version of the passed string. It is simply done by adding the '@CAPITALIZED' statement just before the declaration of the 'originalFunction'.

@CAPITALIZED
originalFunction():
    ...
which is equivalent to
originalFunction = CAPITALIZED(originalFunction)

An important thing that few newbies might mistake is that '@CAPITALIZED' is some sort of built-in special keyword or has some special meaning. Either ways it is NOT true. It is just a function name. The function that you are going to define. The decorator function. you can keep it anyway you want just like a normal function. I like to be in that way because, it tells exactly what the decorator does. So, let go-a-head and implement it.

import sys
def CAPITALIZED(origFunc):
    def modifiedFunction(strArg):
        origFunc(strArg.upper())
        print "This line is appended from modifiedFunction"
    return modifiedFunction

@CAPITALIZED
def originalFunction(stringArg):
    print "The entered String is :"
    print stringArg

def main():
    print "Enter a String : "
    strInput = sys.stdin.readline()
    originalFunction(strInput)
    

if __name__ == "__main__":
    main()

in the above example, the 'originalFunction' is passed as argument to the 'origFunc' and 'stringArg' is passed on to the 'strArg' in the 'CAPITALIZED'. The decorator returns the 'modifiedFunction' to the 'originalFunction'. And now the originalFunction is modified to print the uppercase-d letters of entered string. the output goes like this:

Enter a String : 
dhilipsiva
The entered String is :
DHILIPSIVA
This line is appended from modifiedFunction
More detailed explanation on decorator is coming soon. Comments and corrections are welcomed.