User Tools

Site Tools


python:decorators

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

python:decorators [2013/03/16 17:40] (current)
Line 1: Line 1:
 +=== DECORATORS ===
 +28.05.2009
  
 +==== What are they? ====
 +
 +Python decorators implement the Decorator pattern, but in a limited way. They provide a way to modify of inject code into functions or classes.\\ ​
 +The original proposal of Decorators as an enhancement and the discussion thereby are documented in [[http://​www.python.org/​dev/​peps/​pep-0318/​ | PEP (Python Enhancement Proposal) 318]]
 +
 +
 +==== How to use? ====
 +
 +To decorate a function, you just simply use @<​decorator_name>​ one line above your function definition.
 +
 +<code python>
 +@decorator_name
 +def myFunction():​
 +    print "​myFunction here!"
 +</​code>​
 +
 +When the code is compiled, the myFunction is compiled and then passed to decorator who produces a function-like object to substitute myFunction.\\ ​
 +  * if we use a class as decorator, then they must implement call method (the object return by the decorator must be callable). \\ 
 +  * decorator class constructor is executed at the point of decoration of the function. ​
 +  * decorator constructor receives the function object being decorated (it could be use later in call)
 +
 +
 +
 +==== Some examples please ====
 +
 +<code python>
 +#​!/​usr/​bin/​env python2.6
 +# -*- coding: utf8 -*-
 +
 +  ​
 +class MyDecorator(object):​
 +    def __init__(self,​ f):
 +        self.f = f
 +
 +    def __call__(self,​ a, b):
 +        self.f(a,b)
 +        print "​Running decorated function"​
 +        print "%s * %s = %s " % (a,b,a*b)
 +        ​
 +
 +@MyDecorator
 +def addFunction(a,​ b):
 +    '''​ Original behaviour function adds two numbers '''​
 +    print "​Running original function"​
 +    print "%s + %s = %s " % (a,b,a+b)
 +    ​
 +
 +addFunction(3,​4)
 +</​code>​
 +
 +will return:
 +
 +<​code>​
 +Running original function
 +3 + 4 = 7 
 +Running decorated function
 +3 * 4 = 12 
 +</​code>​
 +
 +You notice, in call method, we first call the initial function, and then modified the behaviour.
 +A slightly modified code, can use a switch to change from the old behavior to the new one.
 +
 +<code python>
 +#​!/​usr/​bin/​env python2.6
 +# -*- coding: utf8 -*-
 +
 +  ​
 +class MyDecorator(object):​
 +    def __init__(self,​ f):
 +        self.f = f
 +
 +    def __call__(self,​ a, b, new = 0):
 +        if new == 1:
 +            print "​Running decorated function"​
 +            print "%s * %s = %s " % (a,b,a*b)
 +        else:
 +            self.f(a,b)
 +
 +        ​
 +
 +@MyDecorator
 +def addFunction(a,​ b):
 +    '''​ Original behaviour function adds two numbers '''​
 +    print "​Running original function"​
 +    print "%s + %s = %s " % (a,b,a+b)
 +    ​
 +
 +addFunction(3,​4)
 +addFunction(5,​2)
 +addFunction(3,​4,​1)
 +</​code>​
 +
 +
 +
 +----
 +
 +Now, the same example using __function as decorator__ instead of a class:
 +
 +
 +<code python>
 +def MyDecorator(fn):​
 +    def decorate(a, b):
 +        fn(a, b)
 +        print "​Running decorated function"​
 +        print "%s * %s = %s " % (a,b,a*b)
 +    return decorate
 +    ​
 +@MyDecorator
 +def addFunction(a,​ b):
 +    '''​ This initial function adds two numbers '''​
 +    print "​Running initial function"​
 +    print "%s + %s = %s " % (a,b,a+b)
 +    ​
 +addFunction(3,​4)
 +</​code>​
 +
 +Now, an interesting example (inspired from [[http://​technofreakatchennai.wordpress.com/​2007/​03/​08/​decorators-in-python/​ | here]]) exemplifying parameter sent to the decorator itself. Change the parameter from * to + to see the difference; the decorator function chooses which method to use further (add- or muldecor)
 +
 +<code python>
 +#​!/​usr/​bin/​env python2.6
 +# -*- coding: utf8 -*-
 +
 +def MyDecorator(operation):​
 +    def adddecor(fn):​
 +        def inner(a, b):
 +            fn(a+b)
 +        return inner
 +    def muldecor(fn):​
 +        def inner(a, b):
 +            fn(a*b)
 +        return inner
 +    # adddecor and muldecor should be referenced first
 +    if operation == '​+':​
 +        return adddecor
 +    elif operation == '​*':​
 +        return muldecor
 +   
 +
 +@MyDecorator('​*'​)
 +def addFunction(a):​
 +    print "​Output %s " % a
 +
 +    ​
 +addFunction(2,​3)
 +</​code>​
 +
 +
 +==== Links ====
 +
 +  * [[ http://​www.siafoo.net/​article/​68 | Python Decorators Don't Have to be (that) Scary ]]
python/decorators.txt ยท Last modified: 2013/03/16 17:40 (external edit)