A simple program using decorators
The following is a simple program using a decorator:
#!/usr/bin/python # A very simple decorator demonstrating the basic concept def timestamp(): import time import datetime ts = time.time() mask = '%Y-%m-%d %H:%M:%S' return datetime.datetime.fromtimestamp(ts).strftime(mask) def add_time_stamp(foo): ''' add_time_stamp is a decorator accepting a function foo ''' def inner(*args, **kargs): ''' inner is the function containing the decoration which in this case consists of printing the timestamp and the calling the outer function ''' print timestamp(), foo(*args, **kargs) return inner @add_time_stamp def show_msg(msg): ''' show_msg takes a single parameter as its argument and prints it to the screen. Note hat he definition of show_msg is preceeded by @add_time_stamp something that is equivalent to the following: def show_msg(msg): print msg show_msg = add_time_stamp(show_msg) ''' print msg if __name__ == "__main__": show_msg('test')
Running this program from the command line, you will see the following output:
2014-05-15 18:04:36 test
As we can see, we are getting the current time-stamp followed by the string we passed (‘test’ in our case) printed in the standard output. The implementation of show_msg knows nothing about the time-stamp, is the decorator that is explicitly print the time-stamp and then calls the original function.
What is interesting in this case though, is the little magic that is going on with the use of the @add_time_stamp right before the definition of show_msg. The “at” sign (@) that goes before the add_time_stamp is a syntactic sugar, saying to python that we want to use the function who’s name is printed right after it to decorate the function that will be defined in the immediately next line!
The following lines of code:
@add_time_stamp def show_msg(msg): print msg
are exactly equivalent to the following:
def show_msg(msg): print msg show_msg = add_time_stamp(show_msg)
The use of the ampersand can be viewed as a syntactic sugar that simplifies the way we are writing the code, making it less verbose and more expressive. Although it might seem like a simple facility, this mechanism very useful and in many cases changes completely the way we write code, something that will become more evident as you start using this approach more and more..
Note that our decorator will work with any function regardless of the number of parameters it takes, because the inner function is using the following signature:
def inner(*args, **kargs):
keeping itself transparent to the specific signature of the function that is been decorated.
At this point you know enough to start writing some more useful snippets that will use decorators in your programs, to see an example keep on reading the next page…