http://exercism.io

http://exercism.io

This is really a very good site where you can learn new languages, and learn new ideas from others’ codes, review and appreciate each others’ code, etc. This is really a great effort and I enjoy it. I am stuck with the initial exercise named “Bob” because it involves unicode as well. But Perl5 and Go languages do not have “Bob” as the 1st exercise. So, as of now, I have some breathing space. Let us see.

Advertisements

Python Decorators

If you are beginner to this, please read them in the following links.
http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/
Bruce Eckel’s articles:
http://www.artima.com/weblogs/viewpost.jsp?thread=240808
http://www.artima.com/weblogs/viewpost.jsp?thread=240845

This blog just tries to find the difference between creating decorators using functions and classes.

Lets say that we have a class CLASS1. The object to which can be created like obj1 = CLASS1(). What if we try to call the object itself as in obj1()? This will call the magic method __call__(self). Let us see this in the python interpreter.

$ python
Python 2.7.5+ (default, Feb 27 2014, 19:39:55) 
[GCC 4.8.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class CLASS1(object):
...     def __init__(self):
...             print "Object initialization"
...     def __call__(self):
...             print "__call__() method"
... 
>>> obj1 = CLASS1()
Object initialization
>>> obj1()
__call__() method
>>> 

Now, with this understanding, we can easily compare and contrast the decorators created by functions and classes as shown below. The argument to the decorators can be manipulated at different levels and in the snippet below, they are identified by the print statements.

def fFunProcessor(fun):
    def __funWrapper(*args, **kwargs):
        print fun.__name__, "starts"
        val = fun(*args, **kwargs)
        print fun.__name__, "ends"
        return val
    return __funWrapper

def fDecoArgProcessor(*decoargs, **decokwargs):
    print "<< 1 >>", decoargs
    def __funProcessor(fun):
        print "<< 2 >>", decokwargs
        def __funWrapper(*args, **kwargs):
            print "<< 3 >>", decoargs, decokwargs
            print fun.__name__, "starts"
            val = fun(*args, **kwargs)
            print fun.__name__, "ends"
            return val
        return __funWrapper
    return __funProcessor

class cFunProcessor(object):
    def __init__(self, fun):
        self.fun = fun
        return
    def __call__(self, *args, **kwargs):
        print self.fun.__name__, "starts"
        val = self.fun(*args, **kwargs)
        print self.fun.__name__, "ends"
        return val

class cDecoArgProcessor(object):
    def __init__(self, *decoargs, **decokwargs):
        self.decoargs = decoargs
        self.decokwargs = decokwargs
        print ">> 1 <<", self.decoargs
        return
    def __call__(self, fun):
        print ">> 2 <<", self.decokwargs
        def __funWrapper(*args, **kwargs):
            print ">> 3 <<", self.decoargs, self.decokwargs
            print fun.__name__, "starts"
            val = fun(*args, **kwargs)
            print fun.__name__, "ends"
            return val
        return __funWrapper

@fFunProcessor
def fPrintLower(s):
    print s.lower()

@fDecoArgProcessor(1, 2, 3, foo = 'bar')
def fPrintUpper(s):
    print s.upper()

@cFunProcessor
def cPrintLower(s):
    print s.lower()

@cDecoArgProcessor(1, 2, 3, foo = 'bar')
def cPrintUpper(s):
    print s.upper()

fPrintLower('Hello World!')
fPrintUpper('Hello World!')
cPrintLower('Hello World!')
cPrintUpper('Hello World!')

From the name of the functions/classes itself, we can understand their purpose like what the function is expecting as input and what it can process. The wrapper function is required to process any arguments to the decorated function. On concluding, I do not see much difference and its just a matter of style or preference.

Happy Programming!