Saturday, July 8, 2023

Python Wrappers and decorators

Python wrappers are functions that are added to another function which then can add additional functionality or modifies its behavior without directly changing its source code. 

They are typically implemented as decorators, which are special functions that take another function as input and apply some changes to its functionality

Wrapper functions can be useful in various scenarios:

Functionality Extension: We can add features like logging, performance measurement, or caching by wrapping our functions with a decorator.

Code Reusability: We can apply a wrapper function or even a class to multiple entities, you can avoid code duplication, and ensure consistent behavior across different components.

Behavior Modification: We can intercept the input arguments, for example, validate the input variable without the need for many assert lines.

import time

def timer(func):

    def wrapper(*args, **kwargs):

        # start the timer

        start_time = time.time()

        # call the decorated function

        result = func(*args, **kwargs)

        # remeasure the time

        end_time = time.time()

        # compute the elapsed time and print it

        execution_time = end_time - start_time

        print(f"Execution time: {execution_time} seconds")

        # return the result of the decorated function execution

        return result

    # return reference to the wrapper function

    return wrapper


@timer

def train_model():

    print("Starting the model training function...")

    # simulate a function execution by pausing the program for 5 seconds

    time.sleep(5) 

    print("Model training completed!")


train_model() 



Below is a retry 


import time


def retry(max_attempts, delay=1):

    def decorator(func):

        def wrapper(*args, **kwargs):

            attempts = 0

            while attempts < max_attempts:

                try:

                    return func(*args, **kwargs)

                except Exception as e:

                    attempts += 1

                    print(f"Attempt {attempts} failed: {e}")

                    time.sleep(delay)

            print(f"Function failed after {max_attempts} attempts")

        return wrapper

    return decorator



@retry(max_attempts=3, delay=2)

def fetch_data(url):

    print("Fetching the data..")

    # raise timeout error to simulate a server not responding..

    raise TimeoutError("Server is not responding.")

fetch_data("https://example.com/data")  # Retries 3 times with a 2-second delay between attempts


References

https://python.plainenglish.io/five-python-wrappers-that-can-reduce-your-code-by-half-af775feb1d5

No comments:

Post a Comment