Skip to content

Decorators

In Python, decorators are a powerful tool that allows you to modify or extend the behavior of functions or methods without changing their actual code. Essentially, a decorator is a function that takes another function as input and returns a new function that enhances or alters the original one in some way.

Basic Concept of Decorators

A decorator is typically defined as a function that accepts a function (or method) as an argument and returns a new function. The new function can modify the behavior of the original function, such as by adding extra functionality before or after calling the original function.

Basic Syntax:

python
def decorator_function(original_function):
    def wrapper_function():
        print("Wrapper executed this before {}".format(original_function.__name__))
        return original_function()
    return wrapper_function

You then apply the decorator to a function using the @ syntax:

python
@decorator_function
def display():
    print("Display function executed")

# Running the decorated function
display()

Output:

Wrapper executed this before display
Display function executed

Explanation:

  1. The @decorator_function syntax is equivalent to writing display = decorator_function(display).
  2. decorator_function accepts the original function (display) and returns a new function (wrapper_function), which calls the original function inside it.
  3. This allows the "wrapper" function to execute code before or after the original function call.

Example: Decorators with Arguments

A more advanced example is using decorators that accept arguments:

python
def decorator_with_args(prefix):
    def decorator_function(original_function):
        def wrapper_function(*args, **kwargs):
            print(f"{prefix}: {original_function.__name__} is being called")
            return original_function(*args, **kwargs)
        return wrapper_function
    return decorator_function

@decorator_with_args("INFO")
def greet(name):
    print(f"Hello {name}")

greet("John")

Output:

INFO: greet is being called
Hello John

Common Use Cases for Decorators:

  1. Logging: Tracking function calls or errors.
  2. Authorization: Checking user permissions before executing a function.
  3. Memoization/Caching: Storing results of expensive function calls.
  4. Timing: Measuring how long a function takes to execute.

Example: Timing Decorator

python
import time

def timing_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Function {func.__name__} took {end_time - start_time} seconds to execute")
        return result
    return wrapper

@timing_decorator
def slow_function():
    time.sleep(2)
    print("Function completed!")

slow_function()

Output:

Function completed!
Function slow_function took 2.002347946167469 seconds to execute

Built-in Decorators

Python provides several built-in decorators, such as:

  • @staticmethod: Declares a method as a static method.
  • @classmethod: Declares a method as a class method.
  • @property: Converts a method into a read-only property.

Decorators are versatile and can be used to add functionality to your code in a clean, reusable, and readable way.

J2J Institute private limited