Search This Blog

Friday 25 April 2014

Decorators

Hi,

Here we will learn what is decorator.
Before that, you may think about decorators are same as Annotations in Java which follows '@' symbol. but in java, Annotation is like telling something to JVM. But here, in Python, Decorators are more than what you are expecting. It is not only just a representation, but also a powerful tool to alter your class, function or any object's functionality on the fly at runtime.
    
    OK, now what is Decorator?
                    Decorator is function or class, which takes another function/class as argument and applies extra features to existing and returns new class/functions.

Simply, it is a process of changing object(everything in Python is Object) at run time.

first we will discuss about inbuilt decorators and then, we will learn how to create our own decorators in Python.

1. @staticmethod
2. @classmethod

1. @staticmethod: By using this decorator, we can call methods from class directly by using class name.
for this, we do not need to create instance of class.

>>>class MyStaticClass(object):
              def  __init__(self):                     
                      pass

              @staticmethod
               def print_value():
                     print 'this is static method'

>>>MyStaticClass.print_value()
this is static method 

In this example, we are not creating any instance of the MyStaticClass class, simply we are calling method direcly by using class name. note that, since it is not instance member, Python never pass instance reference to that method. that is the reason why we are not providing a first default parameter in method which are declared with @staticmethod decorator.

2. @classmethod : This is also predefined decorator which is useful to bind method to class instead of instance. we can call these methods by using class name or using instance or both.

>>>class MyClassMethod(object):
               val = 5
               def __init__(self):
                     pass
               
               @classmethod
               def print_value(cls):
                     print 'given value is '+str(cls.val)

>>>mycls = MyClassMethod()
>>>mycls.print_value()
given value is 5
>>>MyClassMethod.print_value()
given value is 5

Here, we can call class method either by using class name, or by using instance.
This kind of usage is very helpful to create instance on the fly in the middle of program excution.

How to create our own Decorators ?

       In Python, it is possible to create our own decorators to alter object on the fly.

We can create decorators in two ways:
            1. class decorators
            2. function decorators

1. class decorators:  In this case, we can use our own class as a decorator to the another functions.
when compiler goes to the function compilation which is being decorated, it compiles the function first and sends the function object to the class decorator for producing substitution of the function.

       Only constraint on decorators object return is it should be a function. That is it should be callable. for these we need to override __call__() method in our decorator class as follows:

>>> class MyDecorator(object):
          def __init__(self,func):
              print "inside __init__() method"
              func()
             
          def __call__(self):
              print "inside __call__ () method"

>>>@MyDecorator
   def decFunction():
       print "inside function"

output:
inside __init__() method
inside function
inside __call__()

@MyDecorator
def decFunction():
      ......

is equal to 

defFunction = MyDecorator(defFunction)

simpley, it is a process of sending function object through another function or class and assign the result to the original function


2. function decorators:   when you are using decorators, only constrain is it should be callable. i.e. every decorator class should have to override __call__() method.

     Instead of overriding __call__() special function, we can rewrite decorator as follows:

>>>def entryExit(func):
       def new_f():
           print "entering function decorator"
           func()
           print "exit function decorator"
       retunr new_f

>>>@entryExit
   def function():
       print "inside function"

output:
entering function decorator
inside function
exit function decorator

Note that new_f() is a closure because it is capturing the func() method properties

behind the scene, Python compiles function method and sends to entryExit decorator as a parameter. it will executes as closure and output will come as new modified function execution.

By using decorator, we can create an instance which will acts as a another decorator for another class.
simply, decorators are very easy and very complex to use. 
a simple decorators are like "function acts as decorator to another function"
a complex decorators like "a decorator which is a decorator of decorator's decorator and returns decorator's decorator"

 simply, decorators are very powerful in Python.