Saturday, July 19, 2014

51. Python Decorators

Python functions can be decorated with extra code, such as logging and debugging information. They also could be used to validate arguments and run the called function only if certain coditions are met.




In this small program, we can see that a function is treated as a normal parameter in a function call. In function run(), the first argument is function name and the rest of arguments, are packed as a tuple. The run() function returns another function, that is passed to it as the first argument. The arguments in args is unpacked in the function return, calling the other function. After defining, the calc() function, the run() function is executed. The first parameter, is the calc() function and the others are arguments, which will be mapped to the parameter args.


# ex51a.py

def run(f,*args): return f(*args)

def calc(a,b,c): return 2*a+3*b+4*c

A=run(calc,1,2,3)
print(A)



In the main program, the print_function is imported so Python 3 print statements can be used inside Python 2.7. Next, we have a function count(). It will have one argument, a function name. We print the function in the next statement. Next a variable counter is set to zero. This variable is attached to the particular function, so there are separate counters for each function. These outer lines will be only done once, per decorated function, as we will see later. Next we have a function called decorator. If we want, we could choose another name. In the decorator function, all arguments are packed into a tuple args. This is the function, which replaces the original one.




Inside the function, we first increment the counter attached to a particular function. The reason this is done is because this particular function is called each time a function is executed. We print the name of the function, as well as its current counter value. The tuple in args is printed. Then we execute the function and return it.




The way to decorate any function is to write the @ symbol, in the line above the function to be decorated. Now, whenever we call calc1() or calc2(), we will call the decorated function and not the function directly.




The function calc3() and calc4() are also decorated. In calc4(), we only have 2 parameters. The other 3 calc() functions have 3 parameters. The outer function in count is done at function definitions when the counters should are set to 0 for all these 4 functions.




We then use calc1(), calc2() and calc3(). In the first call we set the value returned to variable named a. However in the next few lines, the functions are called without storing them. The important thing is that the counter attached to calc1(), calc2(), and calc3() will be 2 as each function is called twice.




The function calc4() is called a total of four times. Finally, the value in variable a is printed.


# ex51.py
from __future__ import print_function

def count(func):
    print(' func = ',func)
    func.counter = 0
    def decorator(*args):
        func.counter += 1
        print(' counter of {} = {}'.
              format(func.__name__,func.counter))
        print('\t args =',args)
        ret = func(*args)
        print('\t Result =',ret)
        return ret
    return decorator

@count
def calc1(a,b,c):
    return 2*a+3*b+4*c

@count
def calc2(a,b,c):
    return 3*a+4*b+5*c

@count
def calc3(a,b,c):
    return 4*a+5*b+6*c

@count
def calc4(a,b):
    return 9*a+10*b

a=calc1(1,2,3)
calc2(1,2,3)
calc3(1,2,3)
calc1(2,3,4)
calc2(2,3,4)
calc3(2,3,4)
calc4(1,2)
calc4(2,3)
for i in range(2):
    calc4(i,i+1)
print(' Value of a is ',a)



The first 4 printouts correspond to the outer function. The rest of the printouts correspond to the inner decorator() function. The counter of calc1(), becomes 1, after the first calc1(), is done.




These correspond to to calc4() calculations from the for loop. The loop ranges from i = 0 to i = 1. We can see the final value of counter in calc4 is 4. We do not have to use decorators. We can redefine functions, by wrapping one function inside another, as shown below.


# ex51b.py
from __future__ import print_function

def count(func):
    print(' func = ',func)
    func.counter = 0
    def decorator(*args):
        func.counter += 1
        print(' counter of {} = {}'.
              format(func.__name__,func.counter))
        print('\t args =',args)
        ret = func(*args)
        print('\t Result =',ret)
        return ret
    return decorator

def calc1(a,b,c):
    return 2*a+3*b+4*c

def calc2(a,b,c):
    return 3*a+4*b+5*c

def calc3(a,b,c):
    return 4*a+5*b+6*c

def calc4(a,b):
    return 9*a+10*b

# Function decorations
calc1 = count(calc1)
calc2 = count(calc2)
calc3 = count(calc3)
calc4 = count(calc4)

a=calc1(1,2,3)
calc2(1,2,3)
calc3(1,2,3)
calc1(2,3,4)
calc2(2,3,4)
calc3(2,3,4)
calc4(1,2)
calc4(2,3)
for i in range(2):
    calc4(i,i+1)
print(' Value of a is ',a)



5 comments:

  1. Good Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging.

    Python Training in electronic city, Bangalore | #pythontraininginelectroniccity #pythontraining

    DataSciencewithPythonTraininginelectroniccity,Bangalore | #datasciencewithpythontraininginelectroniccity #datasciencewithpythontraining

    ReplyDelete
  2. Python:

    Good Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging.

    https://www.emexotechnologies.com/online-courses/python-training-in-electronic-city/

    ReplyDelete
  3. Good Post! Thank you so much for sharing this pretty post, it was so good to read and useful to improve my knowledge as updated one, keep blogging.

    Python Training in electronic city

    ReplyDelete
  4. nice article.thank you.
    visit
    web programming tutorial
    welookups

    ReplyDelete