DEV Community

Cover image for The Power of Decorators: Separation Of Concerns (SOC) in Python Code
MyExamCloud
MyExamCloud

Posted on

The Power of Decorators: Separation Of Concerns (SOC) in Python Code

Decorators are a useful feature in Python that allows for the separation of concerns within code. This means encapsulating similar functionality in a single place and reducing code duplication. By implementing common functionality within a decorator, we can improve the maintainability and scalability of our code.

A common use case for decorators is in web frameworks such as Django, Flask, and FastAPI. Let's understand the power of decorators by using them as a middleware for logging in Python. In a production setting, it's important to know the time it takes to service a request. This information is shared across all endpoints, so it makes sense to implement it in a single place using decorators.

Let's say we have a function called "service_request()" that is responsible for handling user requests. We want to log the time it takes for this function to execute. One way to do this would be to add logging statements within the function itself, like this:

import time

def service_request():
    start_time = time.time()
    # Function body representing complex computation
    print(f"Time Taken: {time.time() - start_time}s")
    return True
Enter fullscreen mode Exit fullscreen mode

While this approach works, it leads to code duplication. If we have more routes or functions, we'd have to repeat the logging code in each one. This goes against the DRY (Don't Repeat Yourself) principle of clean code. To avoid this, we can use decorators to encapsulate the logging functionality.

The logging middleware would look something like this:

def request_logger(func):
    def wrapper(*args, **kwargs):
            start_time = time.time()
            res = func()
            print(f"Time Taken: {time.time() - start_time}s")
            return res
    return wrapper
Enter fullscreen mode Exit fullscreen mode

In this implementation, the outer function "request_logger" is the decorator that accepts a function as input. The inner function "wrapper" implements the logging functionality, and the original function "func" is called within it. This way, we can use the logging functionality without modifying the code of the original function.

To use this decorator, we simply decorate the service_request function with it using the @ symbol:

@request_logger
def service_request():
    # Function body representing complex computation
    return True
Enter fullscreen mode Exit fullscreen mode

This will automatically pass the service_request function to the "request_logger" decorator, which will log the time taken and then call the original function. This allows us to easily add logging to other service methods in a similar fashion, without repeating code. For example:

@request_logger
def service_request():
    # Function body representing complex computation
    return True

@request_logger
def service_another_request():
    # Function body
    return True
Enter fullscreen mode Exit fullscreen mode

In summary, decorators help us to encapsulate common functionality in a single place, making our code more maintainable and scalable. They also follow the principle of separation of concerns by allowing us to add functionality without modifying the original code. Decorators are a powerful tool in Python and are heavily used in web frameworks and other applications.

MyExamCloud Study Plans
Java Certifications Practice Tests - MyExamCloud Study Plans
Python Certifications Practice Tests - MyExamCloud Study Plans
AWS Certification Practice Tests - MyExamCloud Study Plans
Google Cloud Certification Practice Tests - MyExamCloud Study Plans
MyExamCloud Aptitude Practice Tests Study Plan
MyExamCloud AI Exam Generator

Top comments (0)