Decorators in python for beginners with simplest Real time Use case in 5 minutes

Read Minutes: 5

Decorators dynamically alter the functionality of a function ,method or a class without disturbing the subclass and source code of the function directly.

We must also understand that decorators are not exactly the same as decorator pattern.

Syntax for the decorators are proposed and implemented in accordance to PEP 318.

There might be lot of definitions already about decorators in python but I take this opportunity very well to explain it ,through a real time use case rather giving up a boring theory.

Let’s jump on to ,when and how decorators can be used used in a real time project.

Assume that you have written some functions (here lets consider three) and delivered them to customer already and now your manager comes to you and asks you to include the logging functionality to/in each and every function which you have developed and delivered already.

There comes, the beautiful decorators of python to make your job simple and hassle free.

If you aren’t aware of decorators ,you might end up writing the function for logging and including it in each and every function which is pretty much disturbing the already existing source code and more number of lines of code as well which might lead to some other issues which can’t be predicted unless doing impact analysis.

But with decorators you need not to disturb the function or not necessary to alter the already existing function but still the above problem can be solved.

Free up your shoulders and lets see the technical conversion of the above problem and solution.

Assume that you have three functions foo,bar,choo as below and consider the same is delivered to customer.

def foo():
time.sleep(1)
return “time of foo is {} “.format(ctime().split()[3])

def bar():
time.sleep(1)
return “time of bar is {} “.format(ctime().split()[3])

def choo():
time.sleep(1)
return “time of choo is{}”.format(ctime().split()[3])

print(foo())
print(bar())
print(choo())

All the above function will return the below output.

time of foo is 19:34:10
time of bar is 19:34:11
time of choo is 19:34:12

Now we need to add the logging functionality to all of the above functions and lets see how we can use the concept of decorator.

Step1:

Decorator itself is a function (logger ) which takes another function (func) as argument
def logger(func):

Step2:
Add another inner function to the above in step 1 and lets name it as wrapper and this wrapper is actually going to contain the logic of logging
def wrapper():
variable = func()
<logging code/do something>
return variable
return wrapper

Step3:

Adding Step1+Step2
def logger(func):
def wrapper():
variable = func()
<logging code/do something>
return variable
return wrapper

We are almost done.Stay with me for another minute.

Step4:
Now we will add the actual logging in the place of <do something >
def logger(func): # logger a decorator taking func as argument
def wrapper():
variable = func()
original_result = func()
#Create and configure logger
logging.basicConfig(filename=”newfile.log”, format=’%(asctime)s %(message)s’, filemode=’a’)

#Creating an object
logger=logging.getLogger()

#Setting the threshold of logger to DEBUG
logger.setLevel(logging.DEBUG)

#Test messages
logger.debug(func())
return variable
return wrapper

Hurrah!! We have created a decorator successfully.

Step5(Consuming the decorator):

Just add the decorator to the functions where we need to add just like the below and that's it.

@logger
def foo():
time.sleep(1)
return “time of foo is {} “.format(ctime().split()[3])
@logger
def bar():
time.sleep(1)
return “time of bar is {} “.format(ctime().split()[3])

@logger
def choo():
time.sleep(1)
return “time of choo is{}”.format(ctime().split()[3])

print(foo())
print(bar())
print(choo())

Now we have added the additional feature of logging to already existing functions without modifying the existing source code.

and the final version would be like this and save it as decoxample.py

import time,logging
from datetime import datetime
from time import ctime

def logger(func):
def wrapper():
original_result = func()
#Create and configure logger
logging.basicConfig(filename=”newfile.log”,
format=’%(asctime)s %(message)s’,
filemode=’a’)

#Creating an object
logger=logging.getLogger()

#Setting the threshold of logger to DEBUG
logger.setLevel(logging.DEBUG)

#Test messages
logger.debug(func())

# print(“decorated”,x);
return original_result
return wrapper

@logger
def foo():
time.sleep(1)
return “time of foo is {} “.format(ctime().split()[3])

@logger
def bar():
time.sleep(1)
return “time of bar is {} “.format(ctime().split()[3])

@logger
def choo():
time.sleep(1)
return “time of choo is {}”.format(ctime().split()[3])

print(foo())
print(bar())
print(choo())

and running the above will give the same output as below
time of foo is 19:34:10
time of bar is 19:34:11
time of choo is 19:34:12

along with a log file in newfile.txt with below contents

2019–08–25 21:20:12,256 time of foo is 21:20:12
2019–08–25 21:20:14,282 time of bar is 21:20:14
2019–08–25 21:20:16,305 time of choo is 21:20:16

We are done and problem solved and by the time you might have witnessed the power of decorators in python.

Summary:
Create a decorator function and wrapper with actual logic and use with @ as syntactic sugar above the function where you need to add .

You may motivate me by clicking down the Claps.

Happy pythoning and learning.

https://www.pylabz.com/2019/08/decorators-in-python-for-beginners-with.html

Feel free to reach me at
deepakr6242@gmail.com and deepak.rayathurai@linkedIn and Quora.

proud to be pythonist and aspiring to be sre with AI skills