<jupyter_start><jupyter_text>"Decorators in Python"> "Understanding about a function that takes an other function as an argument and adds further functonallity."- toc: true - badges: true- comments: true- categories: [Programming]- comments: true- author: <NAME>  DecoratorsA decorator is a function that takes an other function as an argument and adds some kinda functonallity and then returns another function.<jupyter_code>def decorator_function(original_function):
    def wrapper_function():
        return original_function()
    return wrapper_function

def display():
    print("Display Function Executed")
decorated_display = decorator_function(display)
decorated_display()
def decorator_function(original_function):
    def wrapper_function():
        print("Wrapper Executed this before {}".format(original_function.__name__))
        return original_function()
    return wrapper_function

def display():
    print("Display Function Executed")
decorated_display = decorator_function(display)
decorated_display()
def decorator_function(original_function):
    def wrapper_function(*args, **kwargs):
        print("Wrapper Executed this before {}".format(original_function.__name__))
        return original_function(*args, **kwargs)
    return wrapper_function

@decorator_function
def display():
    print("Display Function Executed")
display()
@decorator_function
def display_info(name, age):
    print("Display_info executed with arguments: ({}, {})".format(name, age))
display_info("John", 25)<jupyter_output>Wrapper Executed this before display_info
Display_info executed with arguments: (John, 25)<jupyter_text>```pythondecorated_display = decorator_function(display)decorated_display()```**is similar to**```python@decorator_functiondef display():    print("Display Function Executed") the above representation exactly says:display = decorator_functon(display)```  Decorator with Class<jupyter_code>class decorator_class(object):
    
    def __init__(self, original_function):
        self.original_function = original_function
    def __call__(self, *args, **kwargs):
        print("Call method executed before {}".format(self.original_function.__name__))
        return self.original_function(*args, **kwargs)
@decorator_class
def display():
    print("Display Function Executed")

display()
@decorator_class
def display_info(name, age):
    print("Display_info executed with arguments: ({}, {})".format(name, age))
    
display_info("John", 25)<jupyter_output>Call method executed before display_info
Display_info executed with arguments: (John, 25)<jupyter_text>Function for logging the arguments passed to a particulat func<jupyter_code>def my_logger(orig_func):
    import logging
    logging.basicConfig(filename='{}.log'.format(orig_func.__name__,
                                                level= logging.INFO))
    
    def wrapper(*args, **kwargs):
        logging.info(
        'Ran with Args: {}, and Kwargs {}'.format(args, kwargs))
        
    return wrapper
@my_logger
def display_info(name, age):
    print("Display_info executed with arguments: ({}, {})".format(name, age))
display_info("Oill", 45)<jupyter_output><empty_output><jupyter_text>Function for printing execution time of a function<jupyter_code>def my_timer(orig_func):
    import time

    def wrapper(*args, **kwargs):
        t1 = time.time()
        result = orig_func(*args, **kwargs)
        t2 = time.time() - t1
        print('{} ran in: {} sec'.format(orig_func.__name__, t2))
        return result

    return wrapper
@my_timer
def display_info(name, age):
    print("Display_info executed with arguments: ({}, {})".format(name, age))
display_info("Kill", 15)<jupyter_output>Display_info executed with arguments: (Kill, 15)
display_info ran in: 5.0067901611328125e-05 sec<jupyter_text>Applying Multiple decorators for a function```python@my_logger@my_timerdef display_info(name, age):    print("Display_info executed with arguments: ({}, {})".format(name, age))```is completely similar to```pythondisplay_info = my_logger(my_timer(display_info))```<jupyter_code>@my_logger
@my_timer
def display_info(name, age):
    print("Display_info executed with arguments: ({}, {})".format(name, age))
# adds the result in the log file
display_info(2, 4)
@my_timer
@my_logger
def display_info(name, age):
    print("Display_info executed with arguments: ({}, {})".format(name, age))
display_info()<jupyter_output>wrapper ran in: 0.0003368854522705078 sec<jupyter_text>The is an issue running up with the sequence or order of placing decorators.<jupyter_code># Decorators
from functools import wraps


def my_logger(orig_func):
    import logging
    logging.basicConfig(filename='{}.log'.format(orig_func.__name__), level=logging.INFO)

    @wraps(orig_func)
    def wrapper(*args, **kwargs):
        logging.info(
            'Ran with args: {}, and kwargs: {}'.format(args, kwargs))
        return orig_func(*args, **kwargs)

    return wrapper


def my_timer(orig_func):
    import time

    @wraps(orig_func)
    def wrapper(*args, **kwargs):
        t1 = time.time()
        result = orig_func(*args, **kwargs)
        t2 = time.time() - t1
        print('{} ran in: {} sec'.format(orig_func.__name__, t2))
        return result

    return wrapper

import time


@my_logger
@my_timer
def display_info(name, age):
    time.sleep(1)
    print('display_info ran with arguments ({}, {})'.format(name, age))

display_info('Tom', 22)<jupyter_output>display_info ran with arguments (Tom, 22)
display_info ran in: 1.0008461475372314 sec
{'fraction_non_alphanumeric': 0.11705202312138728, 'fraction_numerical': 0.015354046242774566, 'mean_word_length': 4.853065539112051, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 22, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '130443', 'license': 'Apache-2.0', 'n_tokens_mistral': 1686, 'n_tokens_neox': 1617, 'n_words': 433, 'path': '_notebooks/2019-10-15-Decorators-in-python.ipynb', 'repo_name': 'tejakummarikuntla/notes', 'size': '5548'}