Decorator

Decorators are a powerful feature that lets you wrap a function (or class) to modify its behavior without changing its code. Think of it like putting an outfit on a functionโ€”it looks and behaves differently, but the core is the same.


๐Ÿง  What is a Decorator?

A decorator is just a function that takes another function as input, adds something to it, and returns a new function. Read the phylosophy about Proxy Design Pattern

โœ… Create a Simple Decorator

def my_decorator(func):
    def wrapper():
        print("Before function runs")
        func()
        print("After function runs")
    return wrapper

โœ… Using a Decorator

@my_decorator
def say_hello():
    print("Hello!")

say_hello()

Output:

Before function runs
Hello!
After function runs

The @my_decorator is just syntactic sugar for:

say_hello = my_decorator(say_hello)

๐Ÿ›  Why Use Decorators?


๐ŸŽฏ Real-World Example: Timing

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        value = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} took {end - start:.4f} seconds")
        return value
    return wrapper

@timer
def compute():
    time.sleep(1)

compute()

๐Ÿ” Decorator with functools.wraps

When you write decorators, itโ€™s good practice to use @functools.wraps() to preserve the name and docstring of the original function.

from functools import wraps

def log(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__}")
        return func(*args, **kwargs)
    return wrapper


โš™๏ธ Decorator with Arguments

Decorators with arguments (also called parameterized decorators) are super useful when you want to customize the behavior of the decorator at runtime. ๐ŸŽ›๏ธ

๐Ÿ“Œ Basic Structure

def decorator_with_args(arg1, arg2):
    def actual_decorator(func):
        def wrapper(*args, **kwargs):
            print(f"Decorator args: {arg1}, {arg2}")
            return func(*args, **kwargs)
        return wrapper
    return actual_decorator

๐Ÿง  How Decorators with Arguments Work

You're basically writing a function that returns a decorator, which then returns a wrapper function.

@decorator_with_args(args)
โ†’ gives you a decorator
โ†’ which wraps your original function

Usage:

@decorator_with_args("Hello", 123)
def greet(name):
    print(f"Hi, {name}!")

greet("Wendwessen")

๐Ÿ’ก Real Example: Repeating a Function

from functools import wraps

def repeat(n):
    def decorator(func):
	    @wraps(func)
        def wrapper(*args, **kwargs):
            for _ in range(n):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(3)
def greet(name):
    print(f"Hello, {name}!")

greet("Alice")

Output:

Hi!
Hi!
Hi!

๐Ÿข log_if_slow Decorator Implementation

import time
from functools import wraps

def log_if_slow(threshold=0.5):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            start = time.time()
            result = func(*args, **kwargs)
            end = time.time()
            duration = end - start
            if duration > threshold:
                print(f"[SLOW] {func.__name__} took {duration:.2f} seconds.")
            return result
        return wrapper
    return decorator

โšก๏ธExample Usage

@log_if_slow(threshold=0.5)
def slow_function():
    time.sleep(1.2)
    print("Done with slow task.")

@log_if_slow(threshold=0.5)
def fast_function():
    time.sleep(0.2)
    print("Done with fast task.")

slow_function()   # Will log
fast_function()   # Wonโ€™t log

โœ… Example Output:

Done with slow task.
[SLOW] slow_function took 1.20 seconds.
Done with fast task.

๐Ÿงช Summary

Concept Description
Decorator with args A function that returns a decorator
Nested functions One function returns another, which wraps the target function
Useful for Configurable logging, retries, rate limiting, access control

๐Ÿš€ Bonus Challenge (for you!)

๐Ÿ”ฅ Read More on Context Manager


Thanks for Stopping by! Happy learning

Connect with me on

Githubย LinkedInย Gmailย Youtube